Должен ли я включать setState в массив зависимостей useCallback?

    const [active, setActive] = useState(false);

    const onActiveChanged = useCallback(
      isActive => () => {
        // do something
        setActive(isActive);
      },
      [setActive], // or just [] is okay?
    );

При совместном использовании useState и useCallback (или useMemo) следует ли включать setState в массив зависимостей?

@AngelSalazar Метод обновления из useState не запоминается или не сохраняет ту же ссылку?

alanhchoi 18.04.2019 05:10

мой плохой, согласно документам, «React гарантирует, что идентификатор функции setState стабилен и не изменится при повторном рендеринге. Вот почему безопасно исключить из списка зависимостей useEffect или useCallback».

AngelSalazar 18.04.2019 05:17

@AngelSalazar Спасибо за подтверждение! Я также нашел эту часть в github.com/reactjs/reactjs.org/blob/master/content/docs/… Так что просто передача пустого массива должна быть в порядке. Вы можете оставить это как ответ на этот вопрос, или я опубликую ответ на свой вопрос.

alanhchoi 18.04.2019 05:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
26
3
13 603
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Рекомендация для этого также есть на React Docs — Справочник по API хуков.

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

setState(newState);

During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.

Note

React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.

Цель useCallback, как вы правильно намекнули, - запоминать:

useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

А что касается того, для чего предназначен useMemo:

You may rely on useMemo as a performance optimization, not as a semantic guarantee.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Но, как правило, useState стабилен между рендерами (т.е. предварительно запомнен), поэтому вам не нужно запоминать его опять таки.

Тогда возникает вопрос, является ли ваше «сделать что-то» ниже дорогостоящих расчетов? Использование useCallback не должно быть обременительным, но вполне может быть шаблонный код, который вам не нужен, и может почти напрямую использовать вашу функцию setActive.

const [active, setActive] = useState(false);

const onActiveChanged = useCallback(
  isActive => () => {
    // do something
    setActive(isActive);
  },
  [setActive], // or just [] is okay?
);

Еще один способ предотвратить ненужные зависимости в вашем useCallback и других ловушках — использовать функциональные обновления. В результате вы можете получить следующее:

const [active, setActive] = useState(false);
const [expensiveCalc, setExpensiveCalc] = useState(false);

const onExpensiveCalc = useCallback(
  expensiveInput => () => {
    const newState = doExpensiveCalc(expensiveInput);
    expensiveCalc(newState);
  },
  [setActive], // here for completeness
);

return (<>
  // expensive calculation
  <button onClick = {onExpensiveCalc}>Do lengthy calculation</button>
  // cheap calculation, using functional updates
  <button onClick = {() => setActive(prevBoolean => !prevBoolean)}>Cheap Set Active</button>
</>)


Обратите внимание, что есть немного нюанс в том, как работает состояние установки в onClick, и вы должны использовать функцию стрелки, чтобы ваш setActive запускался по клику, а не рендерингу. Это показано во втором ответе выше, но без объяснения причин.

См. также: Что такое useState() в React?

Другие вопросы по теме