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
的淺顯認識。閱讀並借鑑了幾位大神的文章,第一次分享與廣大初學者共同交流進步。努力!奮鬥!💪💪