>React.PureComponent是React在15.3版本添加的一个与React.Component同级的API;
React.memo是React 16.6版本新增的一个高阶函数API。
这两个API本质上都是为了性能优化而生,通过使用这两个API可以减少页面不必要的重新渲染,提高页面性能。
### PureComponent
#### 最基本的应用
父组件:
```javascript
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;
```
子组件
```javascript
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;
```
点击按钮打印执行结果:
![](https://box.kancloud.cn/01add62b28c91e61ba168d88a9846641_486x324.png)
#### PureComponent判断是否需要更新方法为浅比对
![](https://box.kancloud.cn/2bd75262601b8b900aa8914b7857b306_785x579.png)
![](https://box.kancloud.cn/9bee28c3c027a13b23b7abf3f7c59967_711x267.png)
![](https://box.kancloud.cn/ca12ae74c9170537e9aeb2cd39dea532_585x201.png)
改进方法:
![](https://box.kancloud.cn/8bdeef15a61d9b72228dc7ec555d051f_609x148.png)
>[danger]基于这个特性我们应该避免在中引用纯组件时写出如下代码
>```javascript
> // 避免写{}作为默认值,因为每次使用{}时指向的内存地址都不一样,在浏览器控制台中输入{}==={}就可以看到返回值为false
> <PureTestComp value={this.state.pureObj || {}} />
> // 有时候为了提高程序的健壮性,我们必须写默认值,那么就将默认值抽出来做一个单独的变量
> const defaultEmpty = {};
> <PureTestComp value={this.state.pureObj || defaultEmpty} />
>```
<br />
**总结及注意事项**
- 纯组件与组件继承自不同父类
- 纯组件在比较props和state变动与否时使用的是浅比较,在我理解看来浅比较就是比较新的props和老的props中数据的key值是否相同以及key值指向内存的地址是否发生变动,因此
- Number,String等类型变动时因为内存地址直接变动,所以组件会更新
- Object、Array等数据类型,在不修改内存地址时纯组件认为该数据没有发生变动,因此当纯组件需要传递一个对象或者数组作为props时,在修改数据时需要我们重新开辟一块内存空间存储变量。
- 在纯组件中使用shouldComponentUpdate生命周期,组件会舍弃React提供的shallowEqual方法而使用我们设定的更新逻辑。
- 如果在纯组件中只是部分使用了父组件传递的props且props是一个深层数据,这时建议不要使用纯组件,在纯组件中使用shouldComponentUpdate是一件很诡异的事情,违背了我们使用纯组件的初衷,我们可以通过Component和shouldComponentUpdate结合使用来解决多次渲染问题。
>[warning]其实pureComponent组件还会判断state是否发生了变动,但是在我看来使用pureComponent的场景在于纯展示组件,且传递的props数据层级也应该尽可能的浅(因为是浅比较),不建议在pureComponent维护一套state,具体的shallowEqual算法如下
> ```javascript
>if (this._compositeType === CompositeTypes.PureClass) {
> shouldUpdate = !shallowEqual(prevProps, nextProps)
> || !shallowEqual(inst.state, nextState);
>}
>```
<br />
## React.memo
React.memo适用于函数式组件,相当于一个高阶函数,将普通的函数式组件包装成一个类似pureComponent的组件,React.memo接受两个参数
- 第一个参数为要包装的函数式组件
- 第二个参数为一个返回值为true或false的回调函数,用于控制组件的更新状态
经过实验,在只是用第一个参数时,react.memo表现和pureComponent表现是相同的,那么下来的内容主要是讲使用第二个参数时的差异
经过React.memo包装后的组件会增加一个类似shouldComponentUpdate的生命周期(只是类似,其实结果是截然相反的,后面会解释),普通的函数式组件时没有这个生命周期的,也就是说不使用react.memo时函数式组件的更新状态是不可控的。
在官方文档中,第二个参数被叫做areEquals,当没有传递第二个参数时,React会自动进行浅比较然后判断组件的状态去更新组件。通过使用第二个参数,我们可以自己控制组件的更新状态。
![](https://box.kancloud.cn/9748f6c9e5a5a38096f18448e13bf7e2_601x317.png)
>[info]看了红框里的代码,肯定有人注意到第二个回调函数的返回值和shouldComponentUpdate是相反的,上面的代码表示在回调函数中如果title相同时返回true,而不同时返回fasle,似乎与我们理解的不同。
其实这个问题在于我们对areEquals这个值的理解,在shouldComponentUpdate我们返回的是要不要更新,而<u>areEqulas值的意思为是不是相同的,在相同时即为true时我们不更新,在不同时即为fasle时我们更新组件</u>,也就是说第二个回调函数其实也可以理解为是一个shouldComponent<u>Not</u>Update生命周期