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

Edm*_*ues 3 reactjs react-hooks

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

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

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

Joe*_*lay 5

第一次渲染组件时,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();
Run Code Online (Sandbox Code Playgroud)