详解React中Props的浅对比
上一周去面试的时候,面试官我purecomponent
里是如何对比props
的,概念已经牢记脑中,脱口而出就是浅对比,接着面试官问我是如何浅对比的,结果我就没回答上来。
趁着周末,再来看看源码里是如何实现的。
类组件的props对比
类组件是否需要更新需要实现shouldcomponentupdate方法,通常讲的是如果继承的是purecomponent则会有一个默认浅对比的实现。
// 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
的实现如上,我以前以为在声明时默认会实现shouldcomponentupdate
方法,但实际上并没有一个默认的方法。
接下来看看shouldcomponentupdate
方法的调用。
// reactfiberclasscomponent.js function checkshouldcomponentupdate( workinprogress, ctor, oldprops, newprops, oldstate, newstate, nextcontext, ) { const instance = workinprogress.statenode; // 如果实利实现了shouldcomponentupdate则返回调用它的结果 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,而是在对比的时候就返回浅对比的结果。
浅对比的答案都在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数量不同返回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对应的值是否相同。
原来原理是这样简单的对比,如果我面试的时候能够口喷源码,会不会工资更高一些呢?
函数组件的浅对比
函数组件的浅对比方式则使用react.memo方法实现。
// 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函数最为第二个参数。
内部的处理其实是手动创建了一个$$typeof为react_memo_type的reactelement,方便之后的类型判断。
react.memo组件的创建会稍微复杂一些,由于可以传入第二个自定义的compare函数,所以在内部其实会被定义为2种类型的fiber节点。
- 没有传入compare函数的为simplememocomponent。
- 传入了自定义compare函数的为memocomponent。
但是实际对于props的比较都是相同的,默认都是调用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个组件,我也没大看懂,蓝廋香菇,大概是和更新调度相关的。
simplememocomponent的fiber节点实际等于改了个名的函数组件,走流程会直接走到函数组件里,而memocomponent则是套了一层壳,需要先把壳剥开生成子fiber节点,再由子fiber节点的判断走到函数组件里。
以上就是props浅对比的分析了~
以上就是详解react中props的浅对比的详细内容,更多关于react中props的浅对比的资料请关注其它相关文章!