Манипулировать массив с реагирующими крюками - PullRequest
2 голосов
/ 25 марта 2019

Скажем, у меня есть компонент, который получает массив, и я хочу сделать некоторую логику:

const MyComponent = ({ myArray = [] }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([])
  useEffect(() => {
    setProp(myArray.map(x => x + 1))
  }, [myArray])

  return <div />
}

https://codesandbox.io/s/x3kq907r5z

Проблема в том, что я получаю бесконечный цикл.

Я могу исправить ошибку, удалив значение по умолчанию ({ myArray }) и проверив, является ли массив if (Array.isArray(myArray)) setProp(...)

Но я изо всех сил пытаюсь понять: Каков наилучший способ выполнения каких-либо манипуляций с реквизитом (массивом / объектом / и т. Д.) С использованием хуков?

Ответы [ 2 ]

4 голосов
/ 25 марта 2019

При том, как ваш код написан в настоящее время, myArray - это отдельный экземпляр пустого массива в каждом рендере. Это означает, что эффект всегда запускается, так как зависимости всегда менялись!

Это может показаться странным, но рассмотрим следующий фрагмент кода:

const a = [];
const b = [];
console.log(a === b); // false

Простейшим решением этой проблемы было бы либо перенести запасную логику в эффект:

const MyComponent = ({ myArray }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([]);
  useEffect(
    () => {
      setProp(myArray ? myArray.map(x => x + 1) : []);
    },
    [myArray]
  );

  return <div />;
};

Или убедитесь, что один и тот же пустой массив всегда используется по умолчанию:

const empty = [];
const MyComponent = ({ myArray = empty }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([]);
  useEffect(
    () => {
      setProp(myArray.map(x => x + 1));
    },
    [myArray]
  );

  return <div />;
};
0 голосов
/ 19 июля 2019

Но я изо всех сил пытаюсь понять: каков наилучший способ выполнения каких-либо манипуляций с пропеллером (массивом / объектом / и т. Д.) С использованием хуков?

Хуки - это здоровокогда вы пытаетесь манипулировать значением локального состояния, а не опорой.Вы определяете состояние с помощью useState (), и вы используете useEffect () или другие обработчики событий для обновления значения.

Подставка меняется вне компонента, что вызывает функционалкомпонент для повторного выполнения.Итак, чтобы ответить на ваш вопрос: вы не манипулируете реквизитом с помощью крючков.Лучшее, что вы можете сделать, - это предотвратить рендеринг при смене реквизита с помощью useMemo (), но это уже другая тема.

Сказав это, вашим примером может стать:

const MyComponent = ({ myArray = [] }) => {

    console.log("runs when myArray changes");

    const newArray = myArray.map(x => x + 1);

  return <div />
}
...