React中每秒拉取数据,仅在数据变更时更新State避免冗余重渲染
解决方案
直接在定时任务里完成数据拉取、对比和状态更新,不需要额外的ref或双State,就能避免冗余重渲染:
const MyComp = () => { const [data, setData] = useState([]); useEffect(() => { // 定义拉取并更新数据的函数 const fetchAndUpdate = async () => { try { const returnedArray = await apiFetch(); // 对比新数据和当前state,不一致才更新 if (!arraysEqual(returnedArray, data)) { setData(returnedArray); } } catch (err) { console.error('拉取数据失败:', err); } }; // 立即执行一次 fetchAndUpdate(); // 设置每秒执行的定时器 const timer = setInterval(fetchAndUpdate, 1000); // 组件卸载时清除定时器 return () => clearInterval(timer); }, [data]); // 依赖data,确保每次data更新后,回调里能拿到最新的data // 自定义数组对比函数(比JSON.stringify高效,且能处理更复杂的场景) const arraysEqual = (arr1, arr2) => { if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { // 如果是对象,需要递归对比;如果是基本类型直接比较 if (typeof arr1[i] === 'object' && typeof arr2[i] === 'object') { if (!objectsEqual(arr1[i], arr2[i])) return false; } else if (arr1[i] !== arr2[i]) { return false; } } return true; }; // 辅助的对象对比函数 const objectsEqual = (obj1, obj2) => { const keys1 = Object.keys(obj1); const keys2 = Object.keys(obj2); if (keys1.length !== keys2.length) return false; for (const key of keys1) { if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { if (!objectsEqual(obj1[key], obj2[key])) return false; } else if (obj1[key] !== obj2[key]) { return false; } } return true; }; return ( <div> {JSON.stringify(data)} </div> ); };
关键说明:
- 把拉取-对比-更新放在同一个流程里,没有额外的中间状态或ref,减少不必要的组件更新触发点。
- 用自定义对比函数替代
JSON.stringify,后者性能差,还会因为对象键顺序、undefined值等出现误判。 - useEffect依赖数组加入
data,确保回调能捕获到最新的state值,解决之前定时器拿不到最新state的问题。 - 组件卸载时清除定时器,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Aleksa Ristic
相关产品推荐
相关产品推荐

