在 React 中,父组件的重新 render 会引发子组件的重新 render。

子组件的重新渲染

类组件

import React from 'react';

class Child extends React.Component {
  render() {
    console.log('child render');
    return <>This is Child Component</>;
  }
}

export default class App extends React.Component {
  state = {
    count: 0,
  };
  handleClick = () => {
    this.setState({
      count: this.state.count + 1,
    });
  };
  render() {
    return (
      <>
        <div>
          <button onClick={this.handleClick}>click me</button>
          count: {this.state.count}
        </div>
        <Child />
      </>
    );
  }
}

函数组件

import React, { useState } from 'react';

function Child() {
  console.log('child render');
  return <>This is Child Component</>;
}

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <div>
        <button onClick={() => setCount(count + 1)}>click me</button>
        count: {count}
      </div>
      <Child />
    </>
  );
}

在上面的类组件和函数组件中,我们点击按钮 click,会刷新 count 值,导致父组件刷新,而子组件没有做任何状态的变化,但是也一并重新渲染。

为了避免不必要的渲染更新,提高渲染效率,有三个主要的方式:

  • shouldComponentUpdate
  • PureComponent
  • React.memo

类组件

React.PureComponent

class Child extends React.PureComponent {
  render() {
    console.log('child render');
    return <>This is Child Component</>;
  }
}

React.PureComponent 会以浅层对比 props 和 state 的方式实现函数。如果赋值了组件相同的 props 和 state,PureComponent 则可以提高性能,不进行重复渲染。

PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的对比结果。

且 PureComponent 中将跳过所有子组件树的 props 更新,因此确保所有子组件也是 PureComponent。

shouldComponentUpdate

class Child extends React.Component {
  shouldComponentUpdate() {
    return false;
  }
  render() {
    console.log('child render');
    return <>This is Child Component</>;
  }
}

通过使用 shouldComponentUpdate(nextProps, nextState) 进行对比,通过最终返回的 boolean 值决定是否重新渲染。

此方法仅作为性能优化的方式而存在,可以将 this.props 与 nextProps 以及 this.state 与 nextState 进行比较,并返回 false 跳过更新。返回 false 并不会阻止在 state 更改时重新渲染。

不建议经常使用 shouldComponentUpdate

函数组件

React.memo

React.memo 是一个高阶组件,所以它的语法如下:

const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});
const Child = React.memo(function Child() {
  console.log('child render');
  return <>This is Child Component</>;
});

如果组件在相同的 props 的情况下渲染相同的结果,那么可以通过包装在 React.memo 中调用,以此通过记忆组件渲染结果来提高组件的性能。React.memo 仅检查 props 变更,如果实现中拥有 useState、useReducer或useContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。

参考链接