react@16.6.1
ReactFiberClassComponent
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
) {
const instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {
startPhaseTimer(workInProgress, 'shouldComponentUpdate');
const shouldUpdate = instance.shouldComponentUpdate(
newProps,
newState,
nextContext,
);
stopPhaseTimer();
if (__DEV__) {
warningWithoutStack(
shouldUpdate !== undefined,
'%s.shouldComponentUpdate(): Returned undefined instead of a ' +
'boolean value. Make sure to return true or false.',
getComponentName(ctor) || 'Component',
);
}
return shouldUpdate;
}
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
return true;
}
let shouldUpdate = true;
if (this._forcedUpdate) {
shouldUpdate = true;
this._forcedUpdate = false;
} else if (typeof this._instance.shouldComponentUpdate === 'function') {
shouldUpdate = !!this._instance.shouldComponentUpdate(
props,
state,
context,
);
} else if (type.prototype && type.prototype.isPureReactComponent) {
shouldUpdate =
!shallowEqual(oldProps, props) || !shallowEqual(oldState, state);//在此做比对
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
// Added the nonzero y check to make Flow happy, but it is redundant
return x !== 0 || y !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
* Returns true when the values of all keys are strictly equal.
*/
function shallowEqual(objA: mixed, objB: mixed): boolean {
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;
}
// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])
) {
return false;
}
}
return true;
}
export default shallowEqual;
oldProps, newProps是所有属性的集合,就是个object,debug发现 好像每次两个对象的引用都是不同的,那么下面的这句话在比较oldProps, newProps总是返回false(猜测 有待证实)
if (is(objA, objB)) {
return true;
}
在代码里有这么一段
return list.map(item => (
<AppItem
key={item.id}
onDeleteItem={() => this.confirmDeleteItem(item.id)}
copyItem={this.copyAppItem}
data={item}
/>
));
onDeleteItem的写法每次父组件数据更新,都是返回的新的函数,is(objA[keysA[i]], objB[keysA[i]])
这句话永远不会成立,所以直接传递this.confirmDeleteItem进去,在AppItem内部传递id,这样PureComponent才会起作用
模拟props,对shallowEqual进行测试
const data = {
list: [
{
name: "aaa",
sex: "man"
},
{
name: "bbb",
sex: "woman"
}
],
status: true
};
const newData = { ...data };
//如果不解构再赋值因为引用是相同的,如果我改变newData.list[0].name = "geek",
//shallowEqual对比出来返回两者是true,不会重新render。
//但是如果解构,如果我没有改变任何数据shallowEqual返回的都是false,都会重新render
//但是在redux里面 如果我想改变数据才会发dispatch,
//自然需要更新数据(这里面可能会存在数据没改变不需要re-render的情况)
newData.list[0].name = "geek"; //newData和data的list是同一个引用
const props = { data };
const newProps = { data: newData };
console.info(props, newProps);
console.log(shallowEqual(props, newProps)); //false 走render
网友评论