设置状态为当前值时触发Too many re-renders,与React文档描述不符
问题解析:为什么
setFoo(foo)会导致无限重渲染? 首先明确核心误解:你混淆了状态更新的触发时机和React文档描述的适用场景。
文档描述的适用场景
React文档提到的“设置状态为当前值会跳过重渲染”,针对的是在事件处理函数、useEffect、异步回调这类非渲染同步流程中调用setState的情况。比如点击按钮时调用setFoo(foo),此时React会检查状态值是否变化,确认无变化后,最多额外调用一次组件函数,但不会触发DOM更新,也不会形成循环。
你的代码为什么会无限循环?
你在组件函数的顶层同步调用setFoo(foo),这会触发以下循环:
- 组件首次渲染时,执行到
setFoo(foo),启动React的更新流程; - 即使状态值未变化,React仍会调用组件函数以检查是否需要更新;
- 组件函数再次执行时,又会触发
setFoo(foo),再次启动更新流程; - 该循环持续触发,直到React触发“Too many re-renders”的保护机制。
不管你是否使用memo、StrictMode,或是用函数式更新setFoo(val => val),结果都是一样的——只要在组件渲染的同步流程里调用setState,无论是否改变状态,都会触发更新流程,进而导致循环。
关于“结果会被丢弃”的理解
文档里的“结果会被丢弃”,指的是DOM更新的结果。也就是说,当状态无变化时,即使组件函数被额外调用一次,React不会把这次的输出更新到DOM上。但在你的场景里,组件函数被反复调用是因为每次调用都触发了setState,这已经不是单次的额外调用,而是无限循环的触发。
正确的写法
要避免这种情况,必须把setState放在非渲染同步流程的逻辑里,比如事件处理、带合适依赖项的useEffect:
const Component = memo(function () { const [foo, setFoo] = useState('x'); // 仅在组件挂载时执行一次 useEffect(() => { setFoo(foo); // 状态无变化,React会跳过DOM更新,不会触发循环 }, []); return null; });
内容的提问来源于stack exchange,提问作者ruakh
相关产品推荐
相关产品推荐

