詳解React中Props的淺對比
上一周去面試的時候,面試官我PureComponent里是如何對比props的,概念已經(jīng)牢記腦中,脫口而出就是淺對比,接著面試官問我是如何淺對比的,結(jié)果我就沒回答上來。
趁著周末,再來看看源碼里是如何實現(xiàn)的。
類組件的Props對比
類組件是否需要更新需要實現(xiàn)shouldComponentUpdate方法,通常講的是如果繼承的是PureComponent則會有一個默認淺對比的實現(xiàn)。
// ReactBaseClasses.js
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
/**
* Convenience component with default shallow equality check for sCU.
*/
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
PureComponent的實現(xiàn)如上,我以前以為在聲明時默認會實現(xiàn)shouldComponentUpdate方法,但實際上并沒有一個默認的方法。
接下來看看shouldComponentUpdate方法的調(diào)用。
// ReactFiberClassComponent.js
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
) {
const instance = workInProgress.stateNode;
// 如果實利實現(xiàn)了shouldComponentUpdate則返回調(diào)用它的結(jié)果
if (typeof instance.shouldComponentUpdate === 'function') {
const shouldUpdate = instance.shouldComponentUpdate(
newProps,
newState,
nextContext,
);
return shouldUpdate;
}
// PureReactComponent的時候進行淺對比
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
return true;
}
可以看出實際上并沒有單獨寫一個shouldComponentUpdate方法給PureReactComponent,而是在對比的時候就返回淺對比的結(jié)果。
淺對比的答案都在shallowEqual方法里了。
shallowEqual 淺對比
// shallowEqual.js
function shallowEqual(objA: mixed, objB: mixed): boolean {
// 一樣的對象返回true
if (Object.is(objA, objB)) {
return true;
}
// 不是對象或者為null返回false
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
// key數(shù)量不同返回false
if (keysA.length !== keysB.length) {
return false;
}
// 對應key的值不相同返回false
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call(objB, keysA[i]) ||
!Object.is(objA[keysA[i]], objB[keysA[i]])
) {
return false;
}
}
return true;
}
shallowEqual方法原理很簡單了
- 先判斷兩者是否為同一對象。
- 判斷兩者的值是否不為object或為null。
- 對比兩者key的長度。
- 判斷兩者key對應的值是否相同。
原來原理是這樣簡單的對比,如果我面試的時候能夠口噴源碼,會不會工資更高一些呢?
函數(shù)組件的淺對比
函數(shù)組件的淺對比方式則使用React.memo方法實現(xiàn)。
// ReactMemo.js
export function memo<Props>(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
return elementType;
}
React.memo方法同樣支持傳入compare函數(shù)最為第二個參數(shù)。
內(nèi)部的處理其實是手動創(chuàng)建了一個$$typeof為REACT_MEMO_TYPE的ReactElement,方便之后的類型判斷。
React.memo組件的創(chuàng)建會稍微復雜一些,由于可以傳入第二個自定義的compare函數(shù),所以在內(nèi)部其實會被定義為2種類型的Fiber節(jié)點。
- 沒有傳入compare函數(shù)的為SimpleMemoComponent。
- 傳入了自定義compare函數(shù)的為MemoComponent。
但是實際對于Props的比較都是相同的,默認都是調(diào)用shallowEqual方法來對比。
updateSimpleMemoComponent
if (
shallowEqual(prevProps, nextProps) &&
current.ref === workInProgress.ref
) {
// ...
}
updateMemoComponent
// ...
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// ...
至于為什么要分為2個組件,我也沒大看懂,藍廋香菇,大概是和更新調(diào)度相關(guān)的。
SimpleMemoComponent的Fiber節(jié)點實際等于改了個名的函數(shù)組件,走流程會直接走到函數(shù)組件里,而MemoComponent則是套了一層殼,需要先把殼剝開生成子Fiber節(jié)點,再由子Fiber節(jié)點的判斷走到函數(shù)組件里。
以上就是Props淺對比的分析了~
以上就是詳解React中Props的淺對比的詳細內(nèi)容,更多關(guān)于React中Props的淺對比的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React?createRef循環(huán)動態(tài)賦值ref問題
這篇文章主要介紹了React?createRef循環(huán)動態(tài)賦值ref問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01
react router4+redux實現(xiàn)路由權(quán)限控制的方法
本篇文章主要介紹了react router4+redux實現(xiàn)路由權(quán)限控制的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
React Native 集成jpush-react-native的示例代碼
這篇文章主要介紹了React Native 集成jpush-react-native的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
詳解React?如何防止?XSS?攻擊論$$typeof?的作用
這篇文章主要介紹了詳解React?如何防止?XSS?攻擊論$$typeof?的作用,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-07-07
React Hook 父子組件相互調(diào)用函數(shù)方式
這篇文章主要介紹了React Hook 父子組件相互調(diào)用函數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09

