setInterval中useState值不更新:寻求非扩展/prev的持续更新方案
问题描述
在setInterval中尝试将持续变化的数据更新到useState Hook时,始终显示初始值。不想使用扩展运算符或prev构造(这类方法虽有效,但数据每秒更新一次会持续复制数据到内存,导致内存占用不断攀升),是否存在其他可持续更新useState值的方法?
编辑补充内容
数据结构
export const exData = { list: [] as deviceInfo[], add: function (newItem: deviceInfo) { this.list.push(newItem); }, updateData: function (index: number, newValue: deviceInfo) { this.list[index] = newValue; }, getData: function () { return this.list; }, }; export interface deviceInfo { ex1: any; ex2: any; ex3: any; }
持续更新数据的代码(蓝牙低功耗设备扫描)
const handleDiscoverPeripheral = peripheral => { if (infoData === 'NewDevice') { exData.add({ ex1, ex2, ex3, }); } else if (infoData === 'UpdateDevice') { let indexDevices = findIndexList(exData.getData(), ex1); exData.updateData(indexDevices, { ex1, ex2, ex3, }); } };
更新FlatList的代码
const [getData, setData] = useState([]); useEffect(() => { const interval = setInterval(() => { setData(exData.getData()); }, 1000); return () => clearInterval(interval); }, []); useEffect(() => { console.log(getData); }, [getData]);
解决方案
1. 直接在数据变更时触发重渲染(最优方案)
没必要用轮询,既然handleDiscoverPeripheral是数据变化的入口,直接在这里更新组件状态并触发重渲染,完全避免数组复制和轮询开销:
// 用一个空状态专门触发重渲染,不存储实际数据 const [, forceRender] = useState({}); // 用useRef保存最新数据引用,避免复制 const dataRef = useRef(exData.getData()); const handleDiscoverPeripheral = peripheral => { if (infoData === 'NewDevice') { exData.add({ ex1, ex2, ex3 }); } else if (infoData === 'UpdateDevice') { const indexDevices = findIndexList(exData.getData(), ex1); exData.updateData(indexDevices, { ex1, ex2, ex3 }); } // 更新最新数据引用 dataRef.current = exData.getData(); // 触发组件重渲染(空对象每次都是新引用,能触发更新) forceRender({}); }; // FlatList直接使用ref中的最新数据 <FlatList data={dataRef.current} // 其他属性... />
2. 优化轮询逻辑,仅在数据真的变化时更新
如果必须保留轮询逻辑,可以通过对比数据特征避免无效更新,同时用useRef追踪最新数据:
const [, forceRender] = useState({}); const dataRef = useRef(exData.getData()); useEffect(() => { const interval = setInterval(() => { const latestList = exData.getData(); // 可根据实际场景调整对比逻辑,比如设备数量变化、唯一标识变更等 if (dataRef.current.length !== latestList.length) { dataRef.current = latestList; forceRender({}); } }, 1000); return () => clearInterval(interval); }, []);
3. 给数据结构添加通知机制(适合长期维护)
修改exData,添加监听回调,当数据变更时主动通知组件更新,彻底摆脱轮询:
export const exData = { list: [] as deviceInfo[], listeners: [] as Function[], // 添加监听 addListener(callback: Function) { this.listeners.push(callback); }, // 移除监听 removeListener(callback: Function) { this.listeners = this.listeners.filter(cb => cb !== callback); }, // 通知所有监听者 notifyListeners() { this.listeners.forEach(cb => cb()); }, add: function (newItem: deviceInfo) { this.list.push(newItem); this.notifyListeners(); }, updateData: function (index: number, newValue: deviceInfo) { this.list[index] = newValue; this.notifyListeners(); }, getData: function () { return this.list; }, };
组件中使用:
const [, forceRender] = useState({}); const dataRef = useRef(exData.getData()); useEffect(() => { const callback = () => { dataRef.current = exData.getData(); forceRender({}); }; exData.addListener(callback); // 组件卸载时移除监听 return () => exData.removeListener(callback); }, []);
内容的提问来源于stack exchange,提问作者MertCelik
相关产品推荐
相关产品推荐

