React设置相同state时父重渲染子不渲染的原因?
React setState传入相同值时的重渲染差异:父组件执行但子组件不渲染?
问题描述
我在研究React中state setter的重渲染时机时遇到了一个困惑的现象:
- 初始state为9,点击「setNumber to 9」按钮,无任何组件重渲染,符合预期(React用
Object.is()判断state相同则跳过)。 - 首次点击「setNumber to 10」按钮,App和Num组件都打印重渲染日志,符合预期。
- 但再次点击「setNumber to 10」按钮时,App组件触发了重渲染(打印日志),Num组件却没有。我尝试用
memo包裹Num组件,结果依旧如此,这是什么原因?
代码示例
App组件
import { useState } from "react"; import "./App.css"; import Num from "./Components/Num"; function App() { const [number, setNumber] = useState(9); console.log("Component 'App' just re-render."); return ( <div> <h1>If we setNumber to same value, will react do re-render?</h1> <Num number={number} /> <button className="firstBtn" onClick={() => setNumber(9)}> setNumber to 9 </button> <button className="btn" onClick={() => setNumber(10)}> setNumber to 10 </button> </div> ); } export default App;
Num组件
const Num = ({ number }) => { console.log("Component 'num' just re-render."); return ( <div style={{ display: "flex", alignItems: "center", justifyContent: "center", }} > <h3 style={{ marginRight: "8px", color: "#ff5fa2" }}>Number:</h3> <h3>{number}</h3> </div> ); }; export default Num;
原因解析
这是React在不同组件层级的重渲染优化逻辑差异导致的:
1. 父组件(App)的重渲染逻辑
调用setState时,即便新值与当前state完全相同,React不会直接跳过父组件的函数执行。它会先运行App组件的函数体(因此会打印日志),生成新的虚拟DOM,之后对比新旧虚拟DOM,确认没有需要更新的真实DOM内容后,才会跳过DOM更新。简言之:组件函数执行了,但真实DOM没变动。
2. 子组件(Num)的不重渲染逻辑
- 未用
memo包裹时:这是React的自动 bailout 优化在起作用——当子组件的props是原始类型(比如这里的数字number)且新旧值完全一致时,React会自动跳过子组件的重渲染流程。 - 用
memo包裹后:这个优化变成了显式行为——React会对传入的props做Object.is()浅对比,发现number没有变化,直接跳过Num的函数执行与渲染,因此不会打印日志。
额外验证方法
如果想让Num在父组件重渲染时也跟着渲染,可以给Num加一个动态变化的props,比如:
<Num number={number} key={Math.random()} />
此时每次App重渲染时key都会变化,React会认为是新的组件实例,Num就会触发重渲染。
内容的提问来源于stack exchange,提问作者cardsfan
相关产品推荐
相关产品推荐

