При первом рендеринге компонента хук useCallback
примет функцию, переданную в качестве аргумента, и сохранит ее за кулисами.Когда вы вызываете обратный вызов, он вызовет вашу функцию.Пока все хорошо.
Во второй раз, когда компонент визуализируется, хук useCallback
проверит переданные вами зависимости. Если они не изменились, передаваемая вами функция полностьюпроигнорировано !Когда вы вызываете обратный вызов, он вызывает функцию, которую вы передали при первом рендеринге, которая все еще ссылается на те же значения с того момента времени.Это не имеет ничего общего со значениями, которые вы передали в качестве зависимостей - это просто обычные JavaScript-замыкания!
При изменении зависимостей хук useCallback
примет переданную вами функцию и заменит сохраненную функцию,Когда вы вызываете функцию обратного вызова, она вызывает новую версию функции.
Другими словами, нет «замороженных» / условно обновленных переменных - это просто сохранение функции, а затемповторное использование, ничего более причудливого, чем это:)
РЕДАКТИРОВАТЬ: Вот пример, который демонстрирует, что происходит в чистом JavaScript:
// React has some component-local storage that it tracks behind the scenes.
// useState and useCallback both hook into this.
//
// Imagine there's a 'storage' variable for every instance of your
// component.
const storage = {};
function useState(init) {
if (storage.data === undefined) {
storage.data = init;
}
return [storage.data, (value) => storage.data = value];
}
function useCallback(fn) {
// The real version would check dependencies here, but since our callback
// should only update on the first render, this will suffice.
if (storage.callback === undefined) {
storage.callback = fn;
}
return storage.callback;
}
function MyComponent() {
const [data, setData] = useState(0);
const callback = useCallback(() => data);
// Rather than outputting DOM, we'll just log.
console.log("data:", data);
console.log("callback:", callback());
return {
increase: () => setData(data + 1)
}
}
let instance = MyComponent(); // Let's 'render' our component...
instance.increase(); // This would trigger a re-render, so we call our component again...
instance = MyComponent();
instance.increase(); // and again...
instance = MyComponent();