useEffect从数据库加载数据时触发无限循环问题求助
我通过useEffect将数据库查询加载的数据传入脚本更新现有数据,但该useEffect触发了无限循环。相关代码如下,依赖项为从数据库获取的paramsObject:
useEffect(()=>{ console.log("UE1"); // 无限循环中,待调试 setCircles(paramsObject?.circles) }, [paramsObject])
这个useEffect用于更新存储SVG圆形元素的useState状态:
// 创建/初始化圆形数组 const [circles, setCircles] = useState([]);
这部分逻辑对页面数据状态加载至关重要,我不清楚该如何排查解决,以下是更多上下文代码:
// 圆形数组状态 const [circles, setCircles] = useState([]); const { id } = useParams(); const { data } = useQuery(LOAD_DATA); const loadedData = data?.params.find(element => id === element._id); const loadedID = loadedData?._id; const paramsObject = JSON.parse(loadedData?.params || '{}'); useEffect(()=>{ setCircles(paramsObject?.circles) },[paramsObject])
原因分析
无限循环的核心是**paramsObject在每次渲染时都会生成新的引用**。因为你每次调用JSON.parse(loadedData?.params || '{}'),哪怕解析后的内容完全一致,这个函数返回的都是全新的对象/数组。React的依赖对比是浅比较,一旦发现引用变化就会重新执行useEffect;而useEffect里调用setCircles会触发组件重新渲染,重新渲染又会生成新的paramsObject,如此往复形成循环。
解决办法
有几种可行的方案:
方案1:用useMemo缓存
paramsObject
用useMemo包裹paramsObject的生成逻辑,只在loadedData?.params变化时才重新生成,保证引用稳定:const paramsObject = useMemo(() => { return JSON.parse(loadedData?.params || '{}'); }, [loadedData?.params]);方案2:直接监听
loadedData?.params作为依赖
跳过paramsObject,直接把loadedData?.params设为useEffect的依赖,在内部完成解析和状态更新:useEffect(()=>{ const parsed = JSON.parse(loadedData?.params || '{}'); setCircles(parsed?.circles) },[loadedData?.params])方案3:对比数据后再更新状态
在useEffect内先判断paramsObject?.circles与当前circles是否有差异,只有不同时才调用setCircles,避免不必要的状态更新:// 若使用深比较,可引入lodash.isEqual这类工具库 import isEqual from 'lodash.isEqual'; useEffect(()=>{ const newCircles = paramsObject?.circles; if (!isEqual(newCircles, circles)) { setCircles(newCircles); } },[paramsObject, circles])注意:深比较存在一定性能开销,适合数据量较小的场景。
内容的提问来源于stack exchange,提问作者skwidflowz

