React如何识别已更新组件?状态变更触发重渲染机制解析
React 是如何识别组件内部状态变更并触发重渲染的
测试代码
import React from 'react'; const App = () => { console.log('app render'); return ( <div> <Children /> </div> ); }; const Children = () => { const [update, setUpdate] = React.useState(false); console.log('children render'); return ( <div> <button onClick={() => setUpdate(!update)}>update</button> </div> ); }; export default App;
代码运行表现
代码首次加载完成时,控制台会按顺序打印app render、children render两条日志;点击页面上的update按钮后,控制台只会输出children render,外层的App组件不会触发重渲染。
具体原理
入门时学到的三类React组件重渲染触发规则是准确的:
- 组件接收的props发生变化
- 组件自身维护的state发生更新
- 父组件触发重渲染时,未做memo优化的子组件会默认连带重渲染
你提到的props变更感知逻辑是对的:父组件执行render的过程中,React会比对子组件前后接收的props是否变化,以此判断要不要更新子组件。但组件内部state的识别逻辑和props完全不一样:useState返回的setter方法(也就是示例里的setUpdate)本身就是React提供的,调用它的动作就是在主动告知React当前组件需要更新,不存在React主动"探测"state变化的过程。
React从来没有做变量层面的劫持、代理来监听普通变量的变化,整个state触发更新的链路非常直白:
- 组件首次渲染调用
useState时,React会在当前组件对应的内部Fiber节点(React用来存储组件状态、组件树关系的核心数据结构)上,存好初始state值和对应的setter函数。 - 你在事件回调里调用setter、传入新的state值时,setter会直接把新值更新到对应Fiber节点的状态存储位,同时直接给这个Fiber节点打上「待更新」标记,启动React的更新调度流程。
- 调度流程启动后,React只会从标记为待更新的节点开始,向下遍历子树执行渲染逻辑,不会向上遍历父组件节点——这就是示例里点击按钮后只有Children组件重渲染、父组件App完全不触发render的根本原因。
补充:如果你在组件里声明普通let/var变量,哪怕手动修改了它的值,因为没有调用React提供的setter方法,React收不到任何更新通知,根本不会触发重渲染,这也是普通变量不能替代state做响应式数据的核心原因。
内容的提问来源于stack exchange,提问作者seongkuk han
相关产品推荐
相关产品推荐

