PureComponent通过props和state的浅对比来实现shouldComponentUpdate()。除此之外他们几乎完全相同了。
在PureComponent中,如果包含比较复杂的数据结构,当深层的数据发生变化的时候,因为浅对比所以导致界面不会更新。
如果定义了shouldComponentUpdate(),无论组件是否是PureComponent,它都会执行shouldComponentUpdate,然后根据该方法返回值来确定是否更新组件,如果组件没有实现shouldComponentUpdate方法,则会判断该组件是否是PureComponent,如果是的话,会对新旧props,state进行shallowEqual比较,一旦新旧不一致,会触发update.
浅对比(shallowEqual):通过遍历对象上的键执行相等性,并在任何键具有参数之间不严格相等的值时返回false。当所有键的值严格相等时返回ture.
区别点:
1. PureComponent自带通过props和state的浅对比来实现shouldComponentUpdate(),而Component没有。这样不需要开发者实现shouldComponentUpdate,就可以使用PureComponnent来进行简单判断以提升性能。
javaScript中的对象一般是可变的,因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。
let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b); // 打印 2
console.log(foo === bar); // 打印 true
:可以在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;
}
————————————————
版权声明:本文为优快云博主「覃大畅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/u013003052/article/details/87894262
我们先来对is()函数进行分析:
在js中 ‘===’ 可以判断数据类型是否相等,但其实这样方式也并不十分严谨,例如
+0 === -0; // js 打印true
NaN === NaN; // js 打印false
如果我们希望上述的判断结果,+0和-0为false,NaN 与NaN为true,我们可以使用这种方式
1/+0 // 结果为Infinity
1/-0 // 结果为-Infinity
Infinity === -Infinity; // false
解决 NaN === NaN为false,可以通过NaN和自身不相等的特性来解决
x !== x && y !== y
所以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;
}
}
————————————————
版权声明:本文为优快云博主「覃大畅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/u013003052/article/details/87894262
下面以组件的使用来举例:
class ChildComponent extends React.PureComponent {
render() {
return(
<div>
{this.props.numbers}
</div>
)
}
}
class MainComponent extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
numbers: [0]
}
}
handleClick() {
const arr = this.state.numbers;
arr.push(1);
this.setState({
numbers: arr
})
console.log(this.state.numbers)
}
render() {
<div>
<button onClick={this.handleClick} />
<ChildComponent numbers={this.state.numbers}/>
</div>
}
}
————————————————
版权声明:本文为优快云博主「覃大畅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/u013003052/article/details/87894262
然而在MainComponent中去修改umbers时,ChildComponent并没有得到刷新,原因在于js使用的是引用赋值,新的对象简单引用了原始对象,改变新对象虽然影响了原始对象,单对象的地址还是一样,使用===比较的方式相等。而在PureComponent中,会被判定为prop相等而不触发render()。
避免此类问题最简单的方式是,避免使用值可能会突变的属性或状态,而是使用副本来返回新的变量。
handleClick() {
this.setState(prevState => ({
words: [...prevState.words, 'marklar'],
}));
};
另外一种方式是使用Immutable.js