React代码点击计数异常:三次点击输出2,2,3而非预期2,2,2求解析
问题分析与底层逻辑拆解
核心问题:普通变量无法在React渲染周期中保持状态
你定义的count是普通let变量,不是React的状态(useState)。React组件每次触发重渲染(比如调用setThings更新state时),整个App函数会重新执行一遍,这行let count = 1会把count重新初始化为1,根本存不住之前的累加值。
三次点击的具体执行流程
我们一步步理清楚每一次点击的运行逻辑:
第一次点击
- 初始渲染时,
count = 1,state = 'pm'。 - 点击按钮触发
updateThings:count被改成1+1=2- 2是偶数,执行
setThings((pre) => state = 'AM')(这里写法本身有问题,后面说) - 调用
setThings会触发组件重渲染 - 控制台打印
2
- 组件重渲染,
App函数重新跑一遍,let count = 1把count又重置回1,state被更新为'AM'。
第二次点击
- 当前渲染的
count是重渲染后重置的1。 - 点击按钮触发
updateThings:count再次变成1+1=2- 执行
setThings触发重渲染 - 控制台打印
2
- 组件重渲染,
count又被重置为1,state切换为'PM'。
第三次点击(出现3的原因)
React 18在开发模式下会开启严格模式,它会对组件的更新函数执行两次调用,用来检测潜在的副作用问题:
- 当前
count是1。 - 第一次执行
updateThings:count变成2,触发setThings,但React的批量更新机制会暂存这次更新。 - 严格模式触发第二次执行
updateThings:此时count已经是2(同一个更新周期里普通变量不会被重置),所以count = 2+1=3。 - 控制台打印
3,之后组件重渲染,count又被重置为1。
这就是第三次点击输出3的根本原因——严格模式下的重复执行,加上普通变量没有状态持久化,导致count被累加了两次。
额外问题:setThings的写法完全错误
你写的setThings((pre) => state = 'AM')是典型的错误用法:
setThings的回调函数接收的pre是当前的前状态,正确写法应该是返回新状态,比如setThings(pre => 'AM')或者直接setThings('AM')。- 你直接给
state变量赋值,绕开了React的状态更新机制,虽然表面可能有效果,但会导致状态不一致,因为React的state更新是异步且批量的,直接修改变量不会触发正确的重渲染逻辑。
修复方案
要解决问题,核心是把count改成React的状态变量,让它在渲染周期中持久化:
function App() { let [state, setThings] = React.useState('pm'); // 把count改成React状态,初始值1 let [count, setCount] = React.useState(1); let thing = ''; function updateThings() { // 用setCount的回调,基于前状态计算新值,避免异步更新错误 setCount(prevCount => { const newCount = prevCount + 1; // 根据新count值切换AM/PM setThings(newCount % 2 === 0 ? 'AM' : 'PM'); console.log(newCount); return newCount; }); } thing = <div>{state}</div>; return ( <div id="main"> <button type="button" onClick={updateThings} className="w-48 h-20 bg-green-400 rounded-2xl m-20 ring-2 ring-white" > click me </button> {thing} </div> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);
修复后逻辑:
count作为React状态,每次更新都会被持久化,不会在重渲染时重置。- 使用
setCount的回调函数,基于前一个count值计算新值,避免异步更新导致的计数偏差。 - 正确调用
setThings设置新状态,不再直接修改state变量。
此时三次点击控制台会输出2,3,4(符合点击次数的累加逻辑),同时AM/PM的切换也会正确对应count的奇偶性。
内容的提问来源于stack exchange,提问作者Mr. Mysterious
相关产品推荐
相关产品推荐

