首页 > 解决方案 > 从多个组件同时写入单个状态对象

问题描述

在我的 create-react-app 应用程序中,我使用 App.js 中的 useState 挂钩创建了一个对象,我将其作为参数传递给同一组件的 5 个不同实例。这个对象在简单的数字属性名称下包含 5 个不同的数组(因此它们很容易使用 for 循环进行迭代)。

const [ listObj, setListObj ] = useState({ 0: [], 1: [], 2: [], 3: [], 4: [] });

每个组件维护和修改其中一个且只有一个数组(对应于它的编号,因此组件 0 仅修改组件 0,1 仅修改 1 等),并且我使用函数来迭代 listObj 和里面的数组,这样我就可以比较它们的内容。

这些组件每个都有一个通过 App.js 传递给它们的唯一 componentNumber (0-4),以及一个 useEffect 钩子,每当它们想要更新其特定数组时,每个组件看起来都像这样:

useEffect(() => {
  let newArray = functionToGenerateSortedArrays();
  let newListObj = { ...listObj, [ componentNumber ]: newArray };
  setListObj( newListObj );
}, [ (all my state objects that trigger useEffect) ])

当我一次只更新与一个组件有关的内容时,这非常有用。问题是应用程序中有一个功能需要同时更新所有组件。似乎每个人都会获取 listObj 的“旧”副本,使用它来创建具有更新信息的 newListObj,然后使用 newListObj 调用 setListObj,从而覆盖其他组件尝试进行的更改。唯一正确更新的 listObj 数组是该行中的最后一个。

当我尝试实现这个 hacky 解决方案时,我认为自己非常聪明:

useEffect(() => {
  let newArray = functionToGenerateSortedArrays();
  setTimeout(() => {
    let newListObj = { ...listObj, [ componentNumber ]: newArray };
    setListObj( newListObj );
  }, componentNumber * 100 );
}, [ (all my state objects that trigger useEffect) ])

但是,这不起作用。它实际上将 listObj 中的数组立即切换回我想要的值,但在超时触发后它恢复为错误的值。我不知道为什么,但如果有人有任何见解,我很想理解它。我认为这可能与 React 如何“批量”更新状态有关,但找不到任何关于如何阻止 React 这样做的信息,因此我可以测试我的假设。

我是否有任何选项可以以“级联”方式更改 listObj 中的数组值,以免它们相互干扰?是否有另一种不会产生此问题的保存和更新状态的方法?非常感谢你花时间陪伴。

标签: javascriptreactjsreact-hooksuse-effectuse-state

解决方案


这是我们钩子设置器的状态更新回调形式的地方:useState

useEffect(() => {
  let newArray = functionToGenerateSortedArrays();
  setListObj(currentListObj => {
//           ^^^^^^^^^^^^^^
    let newListObj = { ...currentListObj, [ componentNumber ]: newArray };
    return newListObj;
  });
}, [ (all my state objects that trigger useEffect) ])

这样,即使将所有更新函数批处理在一起,它们也将接收当前值,而不是使用效果函数已关闭的过时值。


推荐阅读