从多个组件同时写入单个状态对象
Writing simultaneously to a single state object from multiple components
在我的 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 中的数组值,以免它们相互干扰?是否有另一种不会产生此问题的保存和更新状态的方法?非常感谢您的宝贵时间。
这是我们 state update callback form of the useState
hook's setter:
useEffect(() => {
let newArray = functionToGenerateSortedArrays();
setListObj(currentListObj => {
// ^^^^^^^^^^^^^^
let newListObj = { ...currentListObj, [ componentNumber ]: newArray };
return newListObj;
});
}, [ (all my state objects that trigger useEffect) ])
这样一来,即使所有更新函数一起批处理,它们也会收到当前值,而不是使用效果函数关闭的过时值。
在我的 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 中的数组值,以免它们相互干扰?是否有另一种不会产生此问题的保存和更新状态的方法?非常感谢您的宝贵时间。
这是我们 state update callback form of the useState
hook's setter:
useEffect(() => {
let newArray = functionToGenerateSortedArrays();
setListObj(currentListObj => {
// ^^^^^^^^^^^^^^
let newListObj = { ...currentListObj, [ componentNumber ]: newArray };
return newListObj;
});
}, [ (all my state objects that trigger useEffect) ])
这样一来,即使所有更新函数一起批处理,它们也会收到当前值,而不是使用效果函数关闭的过时值。