Component和PureComponent的区别 介绍 React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过props和state的浅对比来实现 shouldComponentUpate()。
在PureComponent中,如果包含比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断,导致界面得不到更新。
如果定义了 shouldComponentUpdate(),无论组件是否是 PureComponent,它都会执行shouldComponentUpdate结果来判断是否 update。如果组件未实现 shouldComponentUpdate() ,则会判断该组件是否是 PureComponent,如果是的话,会对新旧 props、state 进行 shallowEqual 比较,一旦新旧不一致,会触发 update。
浅对比:通过遍历对象上的键执行相等性,并在任何键具有参数之间不严格相等的值时返回false。 当所有键的值严格相等时返回true。shallowEqual
区别点: PureComponent自带通过props和state的浅对比来实现 shouldComponentUpate(),而Component没有。 PureComponent缺点 可能会因深层的数据不一致而产生错误的否定判断,从而shouldComponentUpdate结果返回false,界面得不到更新。 PureComponent优势 不需要开发者自己实现shouldComponentUpdate,就可以进行简单的判断来提升性能。 为什么PureComponent比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断? JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如 foo={a: 1}; bar=foo; bar.a=2 你会发现此时 foo.a 也被改成了 2。
为了解决这个问题,一般的做法是使用 shallowCopy(浅拷贝)或 deepCopy(深拷贝)来避免被修改,但这样做造成了 CPU 和内存的浪费。
let foo = {a: {b: 1}}; let bar = foo; bar.a.b = 2; console.log(foo.a.b); // 打印 2 console.log(foo === bar); // 打印 true 1 2 3 4 5 可以在fb的shallowEqual方法源码中看到,如下,浅对比只是用Object.is()对Object的value做了一个基本数据类型的比较。
function is(x: mixed, y: mixed): boolean { // 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; } }
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; }
我们先来对is()函数进行分析:
在js中 ‘===’ 可以判断数据类型是否相等,但其实这样方式也并不十分严谨,例如
+0 === -0; // js 打印true NaN === NaN; // js 打印false 1 2 我们希望上述的判断结果,+0和-0为false,NaN与NaN为true,这时候可以用这种方式
1/+0 // 结果为Infinity 1/-0 // 结果为-Infinity Infinity === -Infinity; // false
解决 NaN === NaN为false,可以通过NaN和自身不相等的特性来解决 x !== x && y !== y 1 2 3 4 5 6 所以is()函数首先是通过 ‘===’ 来对数据类型进行比较,然后解决+0/-0和NaN的比较问题。
接下来分析shallowEqual()函数
function shallowEqual(objA: mixed, objB: mixed): boolean { // 首先对两个基本数据类型进行比较 if (is(objA, objB)) { return true; }
// 判断两个数据都为object的情况 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; }
// 获得所有的key const keysA = Object.keys(objA); const keysB = Object.keys(objB);
// 判断两者key的数量是否一致 if (keysA.length !== keysB.length) { return false; }
// 如果key数量相同,使用一层for循环去比较 for (let i = 0; i < keysA.length; i++) { if ( // 判断对象B中是否包含对象A的key,即两者的keys是否一致 !hasOwnProperty.call(objB, keysA[i]) || // 通过is()函数对比A和B的key对应的数据 !is(objA[keysA[i]], objB[keysA[i]]) ) { return false; } }
下面以组件的使用来举例:
例如:
class ChildComponent extends React.PureComponent { render() { return(
然而在MainComponent中去修改numbers时,ChildComponent并没有得到刷新。原因在于js使用的是引用赋值,新的对象简单引用了原始对象,改变新对象虽然影响了原始对象,但对象的地址还是一样,使用===比较的方式相等。而在PureComponent中,会被判定prop相等而不触发render()。
避免此类问题最简单的方式是,避免使用值可能会突变的属性或状态,而是使用副本来返回新的变量。
handleClick() { this.setState(prevState => ({ words: [...prevState.words, 'marklar'], })); };
另外一种方式是使用Immutable.js ———————————————— 版权声明:本文为CSDN博主「覃大畅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/u013003052/…