使用React Hooks解决多组件同时更新全局数组变量的问题
解决ReactN全局数组在组件同时挂载时的更新冲突问题
我有一个ReactN管理的全局数组globalArray,两个组件在挂载时都会向数组添加元素,添加时需要克隆当前数组再新增元素。但由于组件同时挂载,useEffect里克隆的是初始空数组,最终数组里只保留了最后添加的那个元素。另外卸载时的清理逻辑也因为闭包问题,无法获取最新的数组状态。
核心问题分析
问题出在闭包捕获旧状态和同时更新导致的状态覆盖:
- 当两个组件同时挂载时,
useEffect的依赖为空数组,闭包中捕获的globalArray是初始的空数组,各自执行push后设置状态,后执行的组件会覆盖前一个的结果。 - 卸载时的清理函数同样因为闭包,捕获的是组件挂载时的旧数组状态,无法基于最新状态执行移除操作。
解决方案:使用函数式更新
ReactN的setGlobal系列API支持函数式更新,传入的函数会接收当前最新的状态作为参数,确保每次更新都基于最新值操作,彻底避免闭包带来的问题。
修改后的组件代码
ComponentNumberOne.js
import React, { useEffect } from 'react'; import { useGlobal } from 'reactn'; import { clone } from '../../../utils/clone'; const ComponentNumberOne = () => { // 无需直接使用globalArray,忽略第一个返回值 const [, setGlobalArray] = useGlobal('globalArray'); useEffect(() => { // 挂载时添加元素:基于最新状态更新 setGlobalArray(prevArray => { const newArray = clone(prevArray); newArray.push("ComponentNumberOne"); return newArray; }); // 卸载时移除元素:同样基于最新状态操作 return () => { setGlobalArray(prevArray => { const newArray = clone(prevArray); const index = newArray.indexOf("ComponentNumberOne"); // 增加存在性判断,避免找不到元素报错 if (index !== -1) { newArray.splice(index, 1); } return newArray; }); }; }, []); // 依赖保持为空,确保只在挂载/卸载时执行 return ( <div className="ComponentNumberOne"> ComponentNumberOne stuff </div> ); }; export default ComponentNumberOne;
ComponentNumberTwo.js
import React, { useEffect } from 'react'; import { useGlobal } from 'reactn'; import { clone } from '../../../utils/clone'; const ComponentNumberTwo = () => { const [, setGlobalArray] = useGlobal('globalArray'); useEffect(() => { setGlobalArray(prevArray => { const newArray = clone(prevArray); newArray.push("ComponentNumberTwo"); return newArray; }); return () => { setGlobalArray(prevArray => { const newArray = clone(prevArray); const index = newArray.indexOf("ComponentNumberTwo"); if (index !== -1) { newArray.splice(index, 1); } return newArray; }); }; }, []); return ( <div className="ComponentNumberTwo"> ComponentNumberTwo stuff </div> ); }; export default ComponentNumberTwo;
关键修改说明
- 函数式更新替代直接赋值:
通过setGlobalArray(prevArray => {...})获取最新的全局数组状态,确保每次添加/移除操作都基于当前最新值,解决了同时挂载时的状态覆盖问题。 - 移除不必要的状态依赖:
不再直接使用闭包中的globalArray,所以useEffect的依赖数组可以保持为空,保证逻辑只在挂载和卸载时各执行一次。 - 增加安全判断:
卸载时先检查元素是否存在,避免因数组状态变化导致的移除操作报错。
内容的提问来源于stack exchange,提问作者Trevor
相关产品推荐
相关产品推荐

