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

时间:2021-02-06 13:59:55

标签: reactjs react-hooks usecallback

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

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

  1. 我点击第一列的隐藏:setValueWithCallback 运行,将回调设置为引用并设置状态
  2. useEffect 开始,使用更新的数据调用回调
  3. saveToLocalStorageuseCallback 中被调用,data 设置为依赖项

问题出在第 3 步,保存到 localstorage 的内容是 {visible: true}。 我知道如果我改变这一行:

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

为此:

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

它有效,但我无法理解,为什么第一个不行。我想这一定是某种封闭的东西,但我没有看到。

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

2 个答案:

答案 0 :(得分:2)

您代码中的问题是由于 saveToLocalStorage 函数在组件的本地状态上的闭包。

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

useCallback 钩子将更新 saveToLocalStorage 函数的函数引用,但您调用该更新后的函数。相反,您调用您在 callbackRef.current 中保存的函数,它不是更新的函数,而是一个旧函数,它对状态的闭包具有 visible 属性值,两个对象中的值都设置为 {{1} }.

解决方案

您可以通过将 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 }))) ); }, []); 并直接从 callbackRef 钩子内部调用 saveToLocalStorage 函数。

useEffect

答案 1 :(得分:0)

您的 data 是数组类型,只有在状态更新发生时才会响应 shallow comparison,所以基本上它会检查 data 引用的变化而不是它的值变化。这就是为什么当 data's 值更改时您的 saveToLocalStorage 不会重新启动。