PureComponent
?
PureComponent
是优化React
应用程序最重要的方法之一,易于实施,只要把继承类从Component
换成PureComponent
便可,能够减小没必要要的render
操做的次数,从而提升性能,并且能够少写shouldComponentUpdate
函数,节省了点代码。javascript
当组件更新时,若是组件的
props
和state
都没发生改变,render
方法就不会触发,省去Virtual DOM
的生成和比对过程,达到提高性能的目的。java
具体就是因为
PureComponent
的shouldeComponentUpdate
里,实际是对props/state
进行了一个 浅对比,因此对于嵌套的对象不适用,没办法比较出来。react
首先让咱们来看下 PureComponent
的具体实现函数
在React
里,shouldComponentUpdate
源码为:性能
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
复制代码
那咱们再来看看 shallowEqual
的源码究竟是神马玩意?学习
const hasOwn = Object.prototype.hasOwnProperty
function is(x, y) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
return x !== x && y !== y
}
}
export default function shallowEqual(objA, objB) {
if (is(objA, objB)) return true
if (typeof objA !== 'object' || objA === null ||
typeof objB !== 'object' || objB === null) {
return false
}
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
if (keysA.length !== keysB.length) return false
for (let i = 0; i < keysA.length; i++) {
if (!hasOwn.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])) {
return false
}
}
return true
}
复制代码
一看上去可能直接蒙圈。接下来咱们一步一步来看。优化
Object.is()
1. Object.is() 这个函数是用来比较两个值是否相等。但这并不一样于 === 或者 ==
2. '==' 比较,会把 undefined, null, '', 0 直接转换成布尔型false
null == undefined // true
3. '===' 它不会进行类型转换,也就是说若是两个值同样,必须符合类型也同样。可是,它仍是有两种疏漏的状况。
+0 === -0 // true,但咱们期待它返回false
NaN === NaN // false,咱们期待它返回true
复制代码
正由于这些缘由,Object.is()
应运而生ui
// 其实是Object.is()的polyfill
function(x, y) {
// SameValue algorithm
if (x === y) {
// 处理为+0 != -0的状况
return x !== 0 || 1 / x === 1 / y;
} else {
// 处理 NaN === NaN的状况
return x !== x && y !== y;
}
};
复制代码
了解这个咱们再来看看刚才的 shallowEqual
代码this
// 用原型链的方法
const hasOwn = Object.prototype.hasOwnProperty
// 这个函数其实是Object.is()的polyfill
function is(x, y) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
return x !== x && y !== y
}
}
export default function shallowEqual(objA, objB) {
// 首先对基本数据类型的比较
// !! 如果同引用便会返回 true
if (is(objA, objB)) return true
// 因为Obejct.is()能够对基本数据类型作一个精确的比较, 因此若是不等
// 只有一种状况是误判的,那就是object,因此在判断两个对象都不是object
// 以后,就能够返回false了
if (typeof objA !== 'object' || objA === null ||
typeof objB !== 'object' || objB === null) {
return false
}
// 过滤掉基本数据类型以后,就是对对象的比较了
// 首先拿出key值,对key的长度进行对比
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
// 长度不等直接返回false
if (keysA.length !== keysB.length) return false
// key相等的状况下,在去循环比较
for (let i = 0; i < keysA.length; i++) {
// key值相等的时候
// 借用原型链上真正的 hasOwnProperty 方法,判断ObjB里面是否有A的key的key值
// 属性的顺序不影响结果也就是{name:'daisy', age:'24'} 跟{age:'24',name:'daisy' }是同样的
// 最后,对对象的value进行一个基本数据类型的比较,返回结果
if (!hasOwn.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])) {
return false
}
}
return true
}
复制代码
总结: shallowEqual
会比较 Object.keys(state | props)
的长度是否一致,每个 key
是否二者都有,而且是不是 一个引用,也就是只比较了 第一层 的值,确实很浅,因此深层的嵌套数据是对比不出来的。spa
import React, { PureComponent } from 'react'
class App extends PureComponent {
state = {
items: [1, 2, 3]
}
handleClick = () => {
const { items } = this.state
items.pop()
this.setState({ items })
}
render () {
return (<div> <ul> {this.state.items.map(i => <li key={i}>{i}</li>)} </ul> <button onClick={this.handleClick}>delete</button> </div>)
}
}
复制代码
经过这个案例就会发现不管怎么点 delete
按钮 li
的数量都不会改变。就是由于 items
用的是一个引用, shallowEqual
的结果为 true
。改正:
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items: [].concat(items) });
}
复制代码
以上及是刚学习React
的新手对于PureComponent
的浅显认识。阅读并借鉴了几位大神的文章,第一次分享与广大初学者共同交流进步。努力!奋斗!💪💪