useCallback используется для мемоизации коллбеков в компонентах, а useMemo используется для мемоизации значений. По своей сути, эти два хука ничем не отличаются и предназначение у них одно и тоже - хранение данных. Строение идентичное, как и в useEffect и useLayoutEffect, первым аргументом идёт коллбек и вторым - массив зависимостей.
Вот несколько вопросов:
Зачем использовать два метода для одной цели?
Почему бы просто не вернуть данные или JXS из useCallback и использовать их?
Какая разница между этими двумя методами?
Разница в месте вызова
useMemo вызывается исходниками React'а, а useCallback - мы. Примеры обоих функций:
function memoUsed() {
const _ = useMemo(() => {
return ‘insert JSX here’
})
return _
}
function callbackUsed() {
const _ = useCallback(() => {
return ‘insert JSX here’
})
return _()
}
Вуаля, функция useMemo имитирована очень даже прилично, с помощью вызова коллбека (6 и 14 строки). Одна вещь сделано двумя не много разными способами. Дело в том, что в “память” компоненты при пользовании useMemo попадает значение только из return, игнорируя остальное тело функции. В случае с useCallback - коллбек передаётся как строка, без вызова. Но эта разница не влияет на количество маунтов или рендеров компоненты, записи в плане производительности эквивалентны.
В useMemo не рекомендуется использовать другие хуки
Примерчик:
function memoUsed() {
const [state, setState] = useState(null)
const _ = useMemo(() => {
// причинит бесконечный ре-рендер
setState(‘value’)
return ‘insert JSX here’
})
return _
}
function callbackUsed() {
const [state, setState] = useState(null)
const _ = useCallback(() => {
// обычное дело
setState(‘value’)
return ‘insert JSX here’
})
return _()
}
При вызове постороннего хука в useMemo и сопутствующем изменении состояния компонента приведёт к зацикливанию. Так как useMemo отрабатывает при стадии рендеринга, модификация состояния компонента запустит процесс заново. С useCallback таких проблем нет, функция вызывается по пользовательскому событию.
В useMemo аргумент-функция не принимает параметры
Ближе к делу:
function memoUsed() {
const _ = useMemo((arg1) => {
// React игнорирует аргументы
return ‘insert JSX here’
}, [])
return _
}
function callbackUsed() {
const _ = useCallback((what, where) => {
// могут быть использованы в функции
return ‘insert ${what} ${where}’
})
return _(‘JSX’, ‘here’)
}
По документации для useCallback массив зависимостей обязателен
А для useMemo может являться и undefined, что не совсем точно. При отсутствии массива зависимостей в обоих хуках происходит ре-рендер в ста процентах случаев. Это описание является ошибкой, про что заявлено в комментарии в исходном коде.
// allow undefined, but don't make it optional as that is very likely a mistake
В целом, хук useMemo можно заменить судя по всему и существует лишь для абстрактного отделения мемоизации данных от мемоизации методов. Кто знает, может в дальнейших версиях React'a способы хранения данных будут изменяться, так как это очень похоже на наследие классовых компонентов.
diomas
что-то слишком многословно, `useCallback(fn, deps)` это просто `useMemo(() => fn, deps)`
Gary_Ihar
Краткий гайд "как обесценить статью" :)