React useState变量不更新:前两个Increment按钮为何失效?
先看你的代码:
import { useEffect, useState } from "react"; function UseEffectHook() { const [count, setCount] = useState(0) return ( <div> <h1>{count}</h1> <button onClick={() => setCount(count++)}>Increment</button> <button onClick={() => setCount(++count)}>Increment</button> <button onClick={() => setCount(count+1)}>Increment</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>Decrement</button> </div> ) } export default UseEffectHook
核心问题出在违反了React state的不可变原则,结合JavaScript自增运算符的特性,导致前两个按钮无法正确更新state:
第一个按钮:
setCount(count++)count++是后置自增,逻辑是先返回count的当前值,再把局部变量count加1。但这里的count是当前渲染周期的state快照,属于只读常量,修改这个局部变量不会影响React的state。传递给setCount的始终是自增前的旧值(比如初始为0时,点击后传的还是0),state不会变化,页面自然毫无反应。第二个按钮:
setCount(++count)++count是前置自增,先把局部变量count加1,再返回新值。但这里直接修改了state快照的局部变量,属于直接修改state,这是React严格禁止的操作。React依赖state的不可变性追踪变化,直接修改变量不会触发组件重新渲染,页面显示的还是旧的state值,看起来就像没生效。
再看正确写法的逻辑:
第三个按钮:
setCount(count+1)
没有修改原有count变量,而是基于它创建了全新的值count+1传递给setCount。React收到新值后会更新state并触发组件重渲染,因此能正常实现递增。第四个按钮:
setCount(prevCount => prevCount - 1)
这是函数式更新写法,适合新state依赖旧state的场景。它接收上一次的state快照prevCount,返回计算后的新值,既遵循了不可变原则,又避免了闭包导致的旧state问题,所以能正确递减。
关键总结
React的state是不可变的,永远不要直接修改state变量,必须通过钩子返回的更新函数(比如setCount)来更新state,且要传递新的值,或者返回新值的函数,而不是修改原变量。
内容的提问来源于stack exchange,提问作者Fuaad

