const [active, setActive] = useState(false);
const onActiveChanged = useCallback(
isActive => () => {
// do something
setActive(isActive);
},
[setActive], // or just [] is okay?
);
При совместном использовании useState и useCallback (или useMemo) следует ли включать setState в массив зависимостей?
мой плохой, согласно документам, «React гарантирует, что идентификатор функции setState стабилен и не изменится при повторном рендеринге. Вот почему безопасно исключить из списка зависимостей useEffect или useCallback».
@AngelSalazar Спасибо за подтверждение! Я также нашел эту часть в github.com/reactjs/reactjs.org/blob/master/content/docs/… Так что просто передача пустого массива должна быть в порядке. Вы можете оставить это как ответ на этот вопрос, или я опубликую ответ на свой вопрос.





Рекомендация для этого также есть на 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?
@AngelSalazar Метод обновления из useState не запоминается или не сохраняет ту же ссылку?