React setState额外执行问题:多次点击为何出现额外日志?
关于React Hook setState生命周期的疑问
示例代码
let counter = 0; export const Example = () => { const [state, setState] = React.useState({ isActive: false }); console.log(`render`); counter++; return ( <div> <div style={{ border: `1px solid ${state.isActive ? 'red' : 'black'}` }} onMouseDown={() => setState(prevState => (prevState.isActive ? prevState : { isActive: true }))} > Text caption </div> Render - {counter}x </div> ); };
问题描述
多次点击“Text caption”后,页面HTML显示“Render - 2x”,但控制台会打印3次“render”日志。第一次点击时状态发生改变,第二次点击时setState返回了原有状态,为何第二次点击后组件仍会执行渲染?
原因解析
setState的触发逻辑:只要调用
setState,无论最终是否改变状态,React都会先触发组件的重新渲染流程——也就是执行一遍组件函数,所以你会看到控制台多一次render日志。之后React会对比新旧状态的引用是否相等:- 如果状态是新对象(引用不同),就会更新DOM,页面内容同步变化;
- 如果状态是原对象(引用相同),React会跳过DOM更新,但组件函数已经执行过了。
代码执行流程拆解:
- 初始加载:组件第一次执行,控制台打印第1次
render,counter变为1,页面显示“Render - 1x”。 - 第一次点击:
prevState.isActive为false,setState返回新对象{ isActive: true }(引用和原状态不同),状态变化触发组件第二次执行,控制台打印第2次render,counter变为2,页面更新为“Render - 2x”。 - 第二次点击:
prevState.isActive为true,setState直接返回原状态对象(引用和旧状态完全相同)。此时React仍会执行组件函数,控制台打印第3次render,counter变为3,但因为状态引用未变,React判定无需更新DOM,所以页面还是停留在“Render - 2x”。
- 初始加载:组件第一次执行,控制台打印第1次
简单说就是:调用setState一定会触发组件函数执行,但只有当状态的引用真正改变时,才会更新页面DOM。
内容的提问来源于stack exchange,提问作者MarTic
相关产品推荐
相关产品推荐

