🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>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生命周期