🌑

Mocha's Blog

目录
  1. PureComponent
    1. 最基本的应用
    2. PureComponent为浅比对
  2. React.memo

React类组件提速指南

发布时间:2019年3月3日

该篇文章为2019年初在政采云内部做的React优化分享,可能存在过时内容

PureComponent

最基本的应用

import React, { Component } from 'react';
import PureTest from './pureComp';

const titleArr = ['第一个标题', '第二个标题', '第三个标题'];

class PureComp extends Component {
  state = {
    title: '第一个标题',
  }
  componentDidUpdate() {
    console.log(`父组件更新,标题为${this.state.title}`);
  }
  handleClick = () => {
    this.setState({
      title: titleArr[Math.round(Math.random() * 2)],
    });
  }
  render() {
    const { title } = this.state;
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>更改state</button>
        <PureTest title={title} />
      </div>
    );
  }
}

export default PureComp;
import React, { PureComponent } from 'react';

class PureTest extends PureComponent {
  componentDidUpdate() {
    console.log(`pureComponent组件更新,标题为${this.props.title}`);
  }
  render() {
    return (
      <h1>{this.props.title}</h1>
    );
  }
}

export default PureTest;

98294058-DEE1-44B7-BBF1-3B9E7EF056B2

PureComponent为浅比对

6D9F06B1-7940-403F-8B1D-EF01EEC3AA8B

6D9F892C-9811-40AD-8020-9253DBF08234

CB79A67F-283F-478E-AA08-C2FCED7CD2CA

FFF4B686-3BFB-4669-8E46-4C7DE83BC4E7

基于这个特性我们应该避免在中引用纯组件时写出如下代码

// 避免写{}作为默认值,因为每次使用{}时指向的内存地址都不一样,在浏览器控制台中输入{}==={}就可以看到返回值为false
<PureTestComp value={this.state.pureObj || {}} />
// 有时候为了提高程序的健壮性,我们必须写默认值,那么就将默认值抽出来做一个单独的变量
const defaultEmpty = {};
<PureTestComp value={this.state.pureObj || defaultEmpty} />

总结及注意事项

  • 纯组件与组件继承自不同父类
  • 纯组件在比较props和state变动与否时使用的是浅比较,在我理解看来浅比较就是比较新的props和老的props中数据的key值是否相同以及key值指向内存的地址是否发生变动,因此
    • Number,String等类型变动时因为内存地址直接变动,所以组件会更新
    • Object、Array等数据类型,在不修改内存地址时纯组件认为该数据没有发生变动,因此当纯组件需要传递一个对象或者数组作为props时,在修改数据时需要我们重新开辟一块内存空间存储变量。

其实pureComponent组件还会判断state是否发生了变动,但是在我看来使用pureComponent的场景在于纯展示组件,且传递的props数据层级也应该尽可能的浅,不建议在pureComponent维护一套state,具体的shallowEqual算法如下

if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps)
  || !shallowEqual(inst.state, nextState);
}

React.memo

React.memo适用于函数式组件,相当于一个高阶函数,将普通的函数式组件包装成一个类似pureComponent的组件,React.memo接受两个参数

  • 第一个参数为要包装的函数式组件
  • 第二个参数为一个返回值为true或false的回调函数,用于控制组件的更新状态
    经过实验,在只是用第一个参数时,react.memo表现和pureComponent表现是相同的,那么下来的内容主要是讲使用第二个参数时的差异
    经过React.memo包装后的组件会增加一个类似shouldComponentUpdate的生命周期,普通的函数式组件时没有这个生命周期的,也就是说不使用react.memo时函数式组件的更新状态是不可控的。
    在官方文档中,第二个参数被叫做areEquals,当没有传递第二个参数时,React会自动进行浅比较然后判断组件的状态去更新组件。通过使用第二个参数,我们可以自己控制组件的更新状态。26A6CF99-FBD1-47DF-B418-1363074927C4

使用过shouldComponentUpdate的同学可以注意到了第二个回调函数的返回值和shouldComponentUpdate是相反的,在回调函数中如果title相同时返回true,而不同时返回fasle,似乎与我们理解的不同。

其实这个问题在于我们对areEquals这个值的理解,在shouldComponentUpdate我们返回的是要不要更新,而areEqulas值的意思为是不是相同的,在相同时即为true时我们不更新,在不同时即为fasle时我们更新组件,也就是说第二个回调函数其实也可以理解为是一个shouldComponentNotUpdate生命周期

Powered By Hexo.js Hexo and Minima. Support By Oracle & Docker-Compose.

友情链接: 相随