React组件设相同状态值,前两次点击触发重渲染?原因解析
问题分析与解答
为什么两次点击按钮都会打印「Parent Rerendered!」?
React函数组件的默认行为是:只要调用setState方法,无论新状态值和当前值是否相同,都会触发组件重渲染。
在你的代码中:
- 第一次点击按钮时,
stateVar从初始的undefined变为1,状态发生变化,组件正常重渲染,顶层的console.log执行。 - 第二次点击按钮时,你依然调用
setStateVar(1),此时新值和当前stateVar的1完全一致,但React并不会自动跳过这次重渲染流程,组件会重新执行一遍,所以console.log再次打印。
为什么放入useEffect后仅第一次点击打印?
你提到的这个现象,应该是因为实际使用的useEffect指定了依赖数组[stateVar](可能代码示例中漏写了)。当useEffect的依赖数组包含stateVar时:
- 第一次点击后,
stateVar从undefined变为1,依赖项发生变化,useEffect的回调函数执行,打印日志。 - 第二次点击时,
stateVar的值没有改变,依赖项未更新,useEffect不会触发回调,因此不再打印。
如果你的useEffect没有设置依赖数组(如你贴出的代码),理论上每次组件重渲染都会执行回调,第二次点击也会打印。这种情况可能是测试时的误差,或者存在未提及的代码逻辑。
如何实现「仅状态变化时才重渲染」?
如果想让组件在状态值未变化时跳过重渲染,可以通过两种方式优化:
- 函数式更新判断值是否变化
修改按钮的点击逻辑,在setState的函数式更新中判断值是否相同,相同则返回旧值:
<button onClick={() => { setStateVar(prev => { if (prev === 1) return prev; // 值未变化时返回旧值,避免触发重渲染 return 1; }) }} > Rerender UI </button>
- 用
React.memo包裹组件React.memo会对组件的props进行浅比较,若props未变化则跳过重渲染(对于无props的组件,状态值不变时也会跳过):
import React, { useState } from 'react'; const UseCallbackComp = React.memo(() => { const [stateVar, setStateVar] = useState<any>() console.log("Parent Rerendered!") return ( <> <div>UseCallbackComp content</div> <div> <button onClick={() => { setStateVar(1) }} > Rerender UI </button> </div> </> ) }) export default UseCallbackComp;
内容的提问来源于stack exchange,提问作者Garvit
相关产品推荐
相关产品推荐

