React切换state中组件时如何判定触发更新还是重挂载?
React 判定组件更新/重挂载的核心规则
你观察到的现象完全符合React调和(Reconciliation)流程的设计逻辑,核心判断规则非常直接:React对比前后两次渲染生成的虚拟DOM树时,会对同一渲染位置的节点做type字段的全等(===)校验,校验结果直接决定后续渲染行为:
- 若前后节点
type不同:React直接判定二者是完全无关的节点,会完整卸载旧节点——包括执行旧组件的卸载生命周期、清理内部state、绑定的事件与副作用——再从零挂载新节点,走完完整的挂载流程。你场景里从ComponentA切到ComponentB触发unmount/mount,就是因为两次返回的节点type分别是ComponentA和ComponentB两个不同的引用,全等校验不通过。 - 若前后节点
type相同:React判定这是同一个组件/节点,会复用已有的DOM节点/组件实例,仅对比新旧props、state的差异,触发更新流程(执行组件render、componentDidUpdate等更新生命周期),不会触发卸载重挂。你场景里两次传ComponentA仅修改props走更新流程,就是因为两次返回的节点type都是同一个ComponentA的引用,全等校验通过。
对应你提供的Dispatcher实现代码如下:
class Dispatcher extends React.Component { state = { ReactClass: null, props: {} } update = (ReactClass, props) => this.setState({ ReactClass: ReactClass, props: props || {}}); /*... some code for using update method globally*/ render() { let { ReactClass, props } = this.state; if (!ReactClass) return null; return (<ReactClass {...props}/>); } }
场景注意事项
这里的type校验是严格引用相等判断,和组件名字、代码结构没有任何关系:
- 只要你两次调用
update传入的ComponentA是同一个函数/类引用(比如从同一个文件固定import的组件、全局作用域下定义后未被重新赋值的组件),不管props怎么变化,React都会复用已有的组件实例,仅触发更新流程。 - 如果你传入的组件引用发生变化,哪怕组件名字、代码实现和之前完全一致(比如每次渲染时临时定义内联组件、动态import每次拿到新的模块对象、高阶组件每次调用返回新的包装组件),React都会判定type不同,强制触发卸载重挂,之前组件存储的内部state会全部丢失。
容易踩坑的错误写法示例,这种写法每次渲染都会触发子组件重挂:
// 错误:每次render都会生成新的组件引用,导致每次都重挂载 const BadExample = () => { const TempComponent = () => <div>测试内容</div>; return <TempComponent /> }
规则设计逻辑
这套比对规则是React为了平衡diff效率和更新可预测性做的设计:如果不做同位置type的第一层强校验,递归对比整棵树的结构差异会带来极高的性能损耗;用type做快速拦截,可以快速定位需要替换的节点段,同时保证开发者对组件生命周期的触发预期是稳定可控的。
内容的提问来源于stack exchange,提问作者diesel94
相关产品推荐
相关产品推荐

