React代码为何陷入无限循环?相同请求数据仍触发重复渲染
为什么这段React代码会陷入无限循环?
你写的这段代码之所以触发无限循环,核心问题出在对象引用的浅比较上:
原因分析
- 对象引用不同:每次
fetch接口返回的data都是一个全新的JavaScript对象——哪怕它的内容和当前starWarsData完全一致,两者在内存中的引用地址也是不一样的。React检查useEffect依赖数组时,用的是严格相等(===)判断,新对象和旧对象的===结果为false,所以React会判定starWarsData这个依赖项发生了变化。 - 循环触发流程:
- 组件首次渲染,
useEffect执行,发起请求 - 请求返回后调用
setStarWarsData(data),更新状态,触发组件重新渲染 - 重新渲染时,React发现
starWarsData的引用变了,再次执行useEffect - 再次发起请求,得到新对象,更新状态,重新渲染……如此往复形成无限循环
- 组件首次渲染,
解决方法
根据你的需求,有两种常见修复方式:
- 仅挂载时请求一次:如果只需要在组件第一次渲染时获取数据,直接把依赖数组设为空数组
[],这样useEffect只会执行一次:
React.useEffect(function() { fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => setStarWarsData(data)) }, [])
- 内容变化才更新状态:如果确实需要基于
starWarsData的变化触发请求,可以在更新状态前对比内容,只有当内容真的不同时才更新(注意:大对象用JSON.stringify对比性能较差,实际项目建议提取关键字段对比):
React.useEffect(function() { fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => { if (JSON.stringify(data) !== JSON.stringify(starWarsData)) { setStarWarsData(data) } }) }, [starWarsData])
内容的提问来源于stack exchange,提问作者Si Thu
相关产品推荐
相关产品推荐

