Skip to content

React 性能优化(高级)

性能优化对于 React 更加重要

  • shouldComponentUpdate(简称 SCU)
  • PureComponent 和 React.memo
  • 不可变值 immutable.js

shouldComponentUpdate

SCU 基本用法

js
shouldComponentUpdate(nextProps, nextState, nextContext) {
  if (nextState.count !== this.state.count) {
    return true // 可以渲染
  }
  return false // 不重复渲染
}

SCU 默认返回 true

父组件有更新,子组件则无条件也更新

js
// 子组件
class Footer extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <p>{this.props.text}</p>;
  }

  componentDidUpdate() {
    // 当更新父组件时,会一直执行此
    console.log('footer add update');
  }

  // shouldComponentUpdate 默认返回 true
  shouldComponentUpdate(nextProps, nextState, nextContext) {
    if (nextProps.text !== this.props.text) {
      return true; // 可以渲染
    }
    return false; // 不重复渲染
  }

  // React 默认:父组件有更新,子组件则无条件也更新
  // 性能优化对于 React 更加重要
}

// 父组件
class TodoListDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      footerInfo: '底部文字',
    };
  }

  render() {
    return (
      <div>
        <Footer text={this.state.footerInfo} />
      </div>
    );
  }
}

SCU 每次都要吗?

  • 需要时才优化,比如上面的例子
  • 一定要配合不可变值,比如下面的例子

例子

js
// 子组件
class List extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    // 子组件接收参数
    const { list } = this.props;

    return (
      <ul>
        {list.map((item, index) => {
          return (
            <li key={item.id}>
              <span>{item.title}</span>
            </li>
          );
        })}
      </ul>
    );
  }

  // 增加 shouldComponentUpdate
  shouldComponentUpdate(nextProps, nextState, nextContext) {
    // lodash.isEqual 做对象或者数组的深度比较
    if (lodash.isEqual(nextProps.list, this.props.list)) {
      // 相等,则不重复渲染
      return false;
    }
    return true; // 不相等,则渲染
  }
}

SCU 使用总结

  • SCU 默认返回 true,即 React 默认重新渲染所有子组件
  • 必须配合“不可变值”一起使用
  • 可先不用 SCU,有性能问题时再考虑使用

PureComponent 和 memo

  • PureComponent,SCU 中实现了浅比较
  • memo,函数组件中的 PureComponent
  • 浅比较已适用大部分情况(尽量不要做深度比较)

PureComponent 例子

js
class PureComponentDemo extends React.PureComponent {
  constructor(props) {
    super(props);
  }

  shouldComponentUpdate() {
    // 浅比较
  }
}

memo 例子

js
function MyComponent(props) {
  // 使用 props 渲染
}

function areEqual(prevProps, nextProps) {
  // 如果把 nextProps 传入 render 方法的返回结果
  // 与将 prevProps 传入 render 方法的返回结果一致的话则返回 true,
  // 否则返回 false
}

export default React.memo(MyComponent, areEqual);

使用 immutable.js

  • 彻底拥抱“不可变值”
  • 基于共享数据(不是深拷贝),速度好
  • 有一定学习和迁移成本,按需使用

例子

js
const map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
console.log(map1.get('b')); // 2
console.log(map2.get('b')); // 50

基于 MIT 许可发布