React组件到底什么时候render啊

React组件到底什么时候render啊
最新回答
梦里七彩虹

2020-07-01 06:45:23

在给定Demo中,点击Parent组件的div触发更新时,Son组件不会打印“child render!”,因为其命中了React的bailout逻辑,跳过了重新渲染。

React组件重新渲染的核心条件

React组件是否重新渲染取决于Fiber树的构建过程,每个组件的Fiber节点通过以下两种方式之一创建:

  • render:调用组件的渲染函数,根据返回的JSX创建新的Fiber节点。
  • bailout:满足特定条件时,复用上一次更新的Fiber节点,跳过渲染函数调用。
bailout逻辑的触发条件

当组件同时满足以下4个条件时,会进入bailout逻辑,避免重新渲染:

  1. props未变化

    默认情况下,oldProps === newProps(严格相等)。由于JSX是React.createElement的语法糖,每次渲染生成的props对象是新的引用,即使内容未变,引用也不同。

    若组件使用PureComponent或React.memo,则会对props的每个属性进行浅比较,而非严格引用比较。

  2. context未圆氏变化

    组件未使用context,或其context.value未发生变化。

  3. 组件类型未变化

    更新前后的fiber.type相同(如函数组件Son未变为其他类型)。

  4. 无待处理的更新或优先级不匹配

    组件自身未触发更新(如setCount在Parent中调用),且当前更羡腔培新的优先级与组件关联的优先级不一致。

Demo的详细执行流程
  1. 初始渲染

    ReactDOM.render(<App/>, rootEl)触发根节点RootFiber的渲染。

    App、Parent、Son组件依次渲染,生成初始Fiber树。

  2. 点击触发更新

    Parent组件的setCount(count + 1)触发状态更新,标记Parent对应的Fiber节点为需要更新。

  3. 更新阶段的bailout判断

    RootFiber和App

    两者均未直接触发更新,且满足bailout的4个条件(props、context、type、优先级未变),因此复用上一次的Fiber节点,跳过渲染。

    Parent

    由于调用了setCount,不满足条件4,进入render逻辑,重新执行函数体并返回JSX。

    Son

    Son作为Parent的props.children传递,其JSX对象在App和Parent的bailout过程中被复用,导致Son的props引用未变。

    同时满足bailout的其余条件(无context、类型未变、无自身更新),因此跳过渲染。

关键点解析
  • props引用的稳定性:Demo中Son的JSX通过props.children传递,而App和Parent的bailout保证了children的引用未变,从而满足oldProps === newProps。若直接渲染<Son/>(如Parent返回<div><Son/></div>),每次渲染会生成新的JSX对象,导致props引用变化,触发Son重新渲染。

  • 优先级与更新标记:只有直接触发更新的组件(如Parent)会进入render逻辑,其子组件若满足bailout条件则会跳过渲染。

总结

React通过严格的bailout条件优化渲染性能,避免不必要的组件更新。理解以下核心逻辑有助于优化应用:

  • 避免在渲染函数中生成新的对象或函数(如内联函数、对象字面量),可能导致子组件props引用变化。
  • 对稳定props的组件使用React.memo,减少浅比较的开销。
  • 关注context的变化范围,避免不必要的全局重兄唯渲染。