带回调的 useState 不更新 useCallback 依赖项

mar*_*llo 3 reactjs react-hooks usecallback

我在这里做了一个工作示例: https://codesandbox.io/s/magical-flower-o0gyn ?file=/src/App.js

当我单击隐藏按钮时,我想将更新的数据保存到本地存储:

  1. 我单击第一列上的隐藏:setValueWithCallback运行,将回调设置为引用并设置状态
  2. useEffect启动,使用更新的数据调用回调
  3. saveToLocalStorage在设置为依赖项的useCallback情况下被调用data

问题出在第三步,保存到本地存储的内容适用{visible: true}于两者。我知道如果我改变这一行:

const saveToLocalStorage = useCallback(() => {
  localStorage.setItem(
    `_colProps`,
    JSON.stringify(data.map((e) => ({ id: e.id, visible: e.visible })))
  );
}, [data]);
Run Code Online (Sandbox Code Playgroud)

对此:

const saveToLocalStorage = localStorage.setItem(
  `_colProps`,
  JSON.stringify(data.map((e) => ({ id: e.id, visible: e.visible })))
);
Run Code Online (Sandbox Code Playgroud)

它有效,但我无法理解,为什么第一个不起作用。我认为这一定是一些关闭的事情,但我没有看到它。

如果data已经更新,并useEffect运行了回调,为什么它没有在依赖项数组中更新?是的,这个例子很奇怪,第二个解决方案非常好,我只是想演示这个问题。谢谢您的帮助!

You*_*saf 5

saveToLocalStorage代码中的问题是由于组件的本地状态上的函数关闭所致。

在函数内部setValueWithCallback,您saveToLocalStorage使用callback传递给函数的参数保存对setValueWithCallback函数的引用,这就是您的问题所在。

useCallbackhook 将更新函数的函数引用saveToLocalStorage,但您不会调用该更新的函数。相反,您调用保存在其中的函数,该函数callbackRef.current不是更新的函数,而是一个旧函数,该函数对状态有一个闭包,visible两个对象中的属性值都设置为true

解决方案

您可以通过将data作为参数传递给回调函数来解决此问题。您在调用时已经传递了参数callbackRef.current(data),但没有在saveToLocalStorage函数内使用它。

更改saveToLocalStorage以使用从挂钩内部传递的参数useEffect

const saveToLocalStorage = useCallback((updatedData) => {
    localStorage.setItem(
      `_colProps`,
      JSON.stringify(updatedData.map((e) => ({ id: e.id, visible: e.visible })))
    );
}, []); 
Run Code Online (Sandbox Code Playgroud)

解决此问题的另一种方法是摆脱钩子并仅从钩子内部callbackRef调用该函数。saveToLocalStorageuseEffect

useEffect(() => {
    saveToLocalStorage();
}, [data, saveToLocalStorage]);
Run Code Online (Sandbox Code Playgroud)