React Hooks的useCallback如何“冻结”闭包?

时间:2019-02-07 15:57:07

标签: reactjs react-hooks

我想知道React在使用useCallback钩子(以及其他钩子)时是否会“冻结”闭包,除非您将它们传递到inputs中,否则更新钩子中使用的变量参数。

我知道“冻结”这个词很奇怪,所以我创建了一个REPL.it来解释我的意思:https://repl.it/repls/RudeMintcreamShoutcast。请打开Web控制台,然后开始单击count按钮。

如果同一变量的外部/内部值在同一闭包下并引用同一事物,那么它们为何不同?我不熟悉React代码库,这里我可能还缺少一些重要的东西,但是我试图考虑一下如何工作几分钟,却无法了解幕后到底发生了什么。

1 个答案:

答案 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();