You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useState触发Maximum update depth exceeded报错解决方案

报错根因

这个无限循环报错来自两个规则的共同作用:

  1. useEffect/useLayoutEffect 未传入第二个依赖数组参数时,会在组件每一次渲染完成后都执行,而非仅挂载时执行一次。
  2. React 调用 state setter 时,会通过 Object.is() 对比新旧状态:如果值不相等就触发重渲染,如果值相等就直接跳过更新,不会触发重渲染流程。

你的代码触发无限循环的完整流程:

  • 初始 roles 状态是空数组[],组件首次渲染完成后执行effect,调用setRoles(["5nxg5wvb"])。
  • 这里传入的["5nxg5wvb"]是每次执行effect时新创建的数组引用,属于引用类型,哪怕内容和之前的状态一致,Object.is()对比两个不同内存地址的数组永远返回false,React判定状态变化,触发组件重渲染。
  • 重渲染完成后effect再次执行,又生成一个新的数组传入setRoles,再次触发重渲染,循环往复直到触及React的更新嵌套上限,抛出对应错误。

为什么传入字符串就不报错:
字符串是JavaScript原始值类型,当你调用setRoles("5nxg5wvb")时,第一次更新后roles的值已经是这个字符串,后续effect重复执行时传入的同内容字符串和现有状态做Object.is()对比会返回true,React判定状态没有变化,直接跳过重渲染,循环自然终止,报错消失。把useLayoutEffect换成useEffect只是执行时机不同,没有改变上面的循环逻辑,所以报错完全一致。

修复方式

根据实际场景选对应方案即可:

  • 如果只需要在组件挂载时给roles赋一次初始值,直接给effect加空依赖数组,让effect仅在首次挂载时执行一次:
const [roles, setRoles] = useState([]);

useLayoutEffect(() => {
  setRoles(["5nxg5wvb"]);
}, []); // 新增空依赖数组
  • 如果这个值不需要后续动态修改,直接把初始值写在useState的参数里,省掉effect里的额外更新,性能更好:
const [roles, setRoles] = useState(["5nxg5wvb"]);
  • 如果需要根据其他状态动态更新roles,就把对应依赖写到依赖数组里,同时做新旧值判断,避免传入同内容的新引用触发无意义更新。

内容的提问来源于stack exchange,提问作者Alicia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 04:45:37