为什么依赖[currentData]的useEffect会导致组件无限重渲染?
useEffect 依赖数组的比对规则
React 对 useEffect 依赖数组的每一项执行与 Object.is 完全等价的浅比较,不存在内置的深度比对逻辑:
- 基本类型(字符串、数字、布尔值等)直接比对值本身
- 引用类型(对象、数组、函数等)直接比对内存引用地址,即便两个对象的属性、属性值完全一致,只要引用不同就会被判定为依赖变化
- 只要任意一个依赖项与上一次渲染周期的对应值不相等,React 就会在本次 UI 渲染提交完成后,触发对应 useEffect 的回调执行
代码触发无限重渲染的具体原因
这段代码的无限循环来自两个叠加的问题:
- 状态更新函数的参数误用
React 函数组件中由useState返回的setData仅接收单个参数,第二个传入的参数会被直接忽略。你写的setData({ ...currentData }, { data })实际生效的新状态,是通过展开语法生成的全新对象{ ...currentData }——哪怕这个对象的所有属性和旧的currentData完全一致,它的内存引用也是全新的。 - 循环触发的完整链路
- 组件首次挂载,执行 effect 回调,发起
getMyData异步请求 - 异步请求返回后调用
setData,生成全新引用的 state 对象,触发组件重渲染 - 重渲染时生成的新
currentData变量,因为引用和上一次渲染周期的currentData不一致,被 React 判定为依赖发生变化 - 对应 effect 再次触发执行,重新发起异步请求、再次调用
setData生成新的 state,重复上述流程形成死循环
- 组件首次挂载,执行 effect 回调,发起
可落地的修复方案
- 如果仅需要在组件挂载时拉取一次数据,直接将依赖数组改为空数组
[],移除对currentData的依赖即可 - 如果需要基于旧状态合并新拉取的数据,优先使用函数式状态更新写法,避免在 effect 中直接引用旧状态值引入不必要的依赖:
setData((prev) => ({ ...prev, data })) - 如果业务逻辑确实需要监听
currentData变化才重新拉取数据,可以通过useMemo固定值未变化时的对象引用,避免无意义的引用变更触发 effect 执行
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

