6

本文只讨论函数式组件,因为React不再建议使用class component。

过渡期完成以后,函数式组件成为正统的React的开发模型,"component"就用来指代function component,而classes会使用“legacy class components”的方式来指代。未来不会出现“必须使用class组件才能实现”的React行为。

React组件什么时候重新渲染

热身练习:对于下面这个demo,你能够不看实际输出,预测点击每个button分别会产生的结果吗?哪几个组件会重新渲染?为什么是这个结果?
Codesandbox demo

通过查看console.log的输出,你能够知道哪几个组件实际re-render了。从这个例子可以分析出React的重渲染的规律:

(1). 当Parent re-render时,Child也会re-render,除非以下2种情况之一发生:

  • 父组件渲染的JSX tree中,在某个位置使用的<Child/>对象(react element,即React.createElement()返回的对象)与上次渲染时相同(在同一个位置使用同一个对象引用),这时Child组件不会re-render。
  • Child组件被React.memo装饰,并且传给Child组件的props与上次渲染相同。

    • 这种情况可以理解为React.memo帮我们缓存了上次渲染时使用的<Child/>jsx element对象。即
const Component = React.memo(({count}) => {
     console.log('Component re-render')
     return <div>Count: {count}</div>
})

等价于

const Component = ({count}) => {
        return React.useMemo(() => {
                console.log('Component re-render')
                return <div>Count: {count}</div>
        }, [count]) // deps数组包含所有Parent可能传入的props value
}

(2). 当Child的状态更新并且re-render的时候,Parent不会re-render,只有Child以及它的后裔组件会re-render。并且Child组件re-render的时候,收到的props与上次渲染相同
(3). 如果通过setState设置的新state与当前state相同,则不会触发re-render。(bail out)

如何做性能优化

基于上面总结的React重渲染规律,我们可以推导出以下的性能优化方式:

  • 使用React.memo装饰组件,使得它在props相同的时候不重新渲染(它下面的子树也不会重新渲染)。
  • 使用React.usememo来缓存计算结果、或者jsx element。它有2个方面的作用:

    • 一方面,能够避免重复计算。当依赖与上次相同的时候,计算函数不会被调用,而是直接取上次缓存的计算结果。
    • 另一方面,可以用来避免子组件的re-render。前面已经说了,如果<Child/>这个jsx element对象与上次渲染是同一个对象,那么Child就不会被重新渲染(它的render函数不会被调用)。因此,Parent可以使用React.usememo来缓存上次渲染时使用的<Child/>jsx element对象,避免Child组件重新渲染。
  • Parent主动优化,给Child传入相同的props.someJSX(Parent可以使用useMemo来避免Child的props值变化)。当Child组件将props.someJSX渲染出来的时候,React会发现这个React element与上次渲染时相同,于是不会尝试diff这个React element下面的节点

    • 因此,如果Parent知道Child的props.someJSX是不需要更新的,可以传递一个缓存的值给Child,避免这颗子树的diff和更新。props.children经常能够这样优化。
  • 如果Parent根本就没有重新渲染,re-render的起点是Child,此时Child的所有props必定与上次渲染相同。这种情况下,如果Child组件将props.someJSX渲染出来,React会发现这个React element与上次渲染时相同,于是不会尝试diff这个React element下面的节点。props.children经常能够满足这种条件。

扩展阅读

redux-react作者编写的React渲染总结


csRyan
1.1k 声望198 粉丝

So you're passionate? How passionate? What actions does your passion lead you to do? If the heart doesn't find a perfect rhyme with the head, then your passion means nothing.