TL; DR;
useMemo
для запоминания результата вычисления между вызовами функции и между рендерами useCallback
для запоминания самого обратного вызова (ссылочное равенство) между рендерами useRef
для сохранения данных между рендерами (обновление не запускает повторный рендеринг) useState
для хранения данных между рендерами (обновление будет запускать ре рендеринг) Длинная версия:
useMemo
фокусируется на избежании тяжелых вычислений.
useCalback
фокусируется на другом: исправляет проблему с производительностью, когда встроенные обработчики событий, такие как onClick={() => { doSomething(...); }
, делают PureComponent
дочерний повторный рендеринг (так как выражение функции там каждый раз ссылочно отличается)
Это говорит useCallback
ближе к useRef
, чтобы еще больше запомнить результат расчета.
PS Изучая документы , я согласен, что это выглядит странно.
blockquote>
useCallback
вернет запомненную версию обратного вызова, которая изменяется только в случае изменения одного из входов. Это полезно при передаче обратных вызовов оптимизированным дочерним компонентам, которые полагаются на равенство ссылок для предотвращения ненужных рендеров (например, shouldComponentUpdate).В примере
предположим, что у нас есть дочерний элемент
[1141 ] Следующий код переопределяет дочерний элемент каждый раз, когда переопределяется родительский элемент - поскольку встроенная функция каждый раз референциально отличаетсяPureComponent
, который будет повторно визуализировать только после изменения его
props
function Parent({ ... }) { const [a, setA] = useState(0); ... return ( ...
{ doSomething(a); }} /> ); } Мы можем справиться с этим с помощью
useCallback
[ 1143] Но как толькоfunction Parent({ ... }) { const [a, setA] = useState(0); const onPureChange = useCallback(() => {doSomething(a);}); ... return ( ...
); } a
изменится, мы обнаружим, чтоonPureChange
, который мы создали, и запомнившийся для нас React все еще указывает на старое значениеa
! У нас ошибка вместо проблемы с производительностью! Это связано с тем, чтоonPureChange
использует функцию закрытия для доступа к переменным (не для доступа по имени переменной). Чтобы сделать это правильно, нам нужно дать React знать, куда добавитьonPureChange
, и заново создать / запомнить (запомнить) новую версию, которая указывает на правильные данные. И здесь нам нужен второй аргумент:
const [a, setA] = useState(0); const onPureChange = useCallback(() => {doSomething(a);}, [a]);
Теперь, если
a
изменено, React повторно рендерит компонент (это ходuseState
). И во время повторного рендеринга он обнаруживает, что входные данные дляonPureChange
отличаются, и возникает необходимость заново создать / запомнить новую версию обратного вызова. Наконец-то и все работает!