1

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

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

  1. 我单击第一列上的隐藏:setValueWithCallback运行,将回调设置为 ref 并设置状态
  2. useEffect开始,使用更新的数据调用回调
  3. saveToLocalStorage被调用,在一个useCallback设置data为依赖

问题出在第 3 步,保存到本地存储的内容{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运行了回调,为什么它没有在依赖数组中更新?是的,这个例子很奇怪,第二个解决方案很好,我只是想演示这个问题。谢谢您的帮助!

4

2 回答 2

3

您的代码中的问题是因为saveToLocalStorage在组件的本地状态上关闭了函数。

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

useCallback钩子将更新函数的函数引用,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 })))
    );
}, []); 

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

useEffect(() => {
    saveToLocalStorage();
}, [data, saveToLocalStorage]);
于 2021-02-06T15:24:32.693 回答
0

data是数组类型,并且仅shallow comparison在发生状态更新时才做出反应,因此基本上它会检查data参考更改而不是其值更改。data's这就是为什么值更改时不会重新启动您的 saveToLocalStorage 的原因。

于 2021-02-06T14:11:21.077 回答