我想知道React在使用useCallback
钩子(以及其他钩子)时是否会“冻结”闭包,除非您将它们传递到inputs
中,否则更新钩子中使用的变量参数。
我知道“冻结”这个词很奇怪,所以我创建了一个REPL.it来解释我的意思:https://repl.it/repls/RudeMintcreamShoutcast。请打开Web控制台,然后开始单击count
按钮。
如果同一变量的外部/内部值在同一闭包下并引用同一事物,那么它们为何不同?我不熟悉React代码库,这里我可能还缺少一些重要的东西,但是我试图考虑一下如何工作几分钟,却无法了解幕后到底发生了什么。
答案 0 :(得分:4)
第一次渲染组件时,useCallback
钩子会将传递的函数作为其参数,并将其存储在幕后。当您调用回调时,它将调用您的函数。到目前为止,一切都很好。
第二次呈现组件时,useCallback
钩子将检查您传入的依赖项。如果它们没有更改,则传入的函数将被完全忽略!当您调用回调时,它将调用您在第一个渲染器上传递的函数,该函数在该时间点仍引用相同的值。这与您作为依赖项传入的值无关,只是普通的JavaScript闭包!
当依赖项更改时,useCallback
挂钩将采用您传入的函数并替换其已存储的函数。调用回调时,它将调用该函数的 new 版本。
换句话说,没有“冻结” /有条件更新的变量-它只是存储一个函数然后重用它,仅此而已:)
编辑:以下示例演示了纯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();