什么是shouldComponent?
- React中的一个生命周期,
- 运行时机:在getDerivedStateFromProps之后,render之前执行
- 触发条件:
a. props更新
b. setState
forceUpdate不会导致shouldComponentUpdate的触发
- 作用,如果返回true,那组件就继续render;如果返回false,组件就不更新渲染
什么是pureComponent
- React的一种组件类;
- 与React.Component很相似。两者的区别在于React.Component中,并没有实现shouldComponentUpdate,需要继承类自己实现。而React.PureComponent中,会浅层对比prop和state,如果内容相同,那么组件将会跳过此次的render更新;
- React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。
纯组件的含义,就是传入相同的props对象,总会有相同的渲染内容。
类似于纯函数的定义
4.判断步骤:
如果 PureComponent 里有 shouldComponentUpdate 函数的话,直接使用 shouldComponentUpdate 的结果作为是否更新的依据。
没有 shouldComponentUpdate 函数的话,才会去判断是不是 PureComponent ,是的话再去做 shallowEqual 浅比较。
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)
);
}
从上面的代码就可以看出,pureComponent不是实现了shouldComponentUpdate的Component,而是在对比的时候就返回浅对比的结果。
- PureComponent不可滥用,他使用在class组件内,只有那些状态和属性不经常的更新的组件我们用来做优化,对于经常更新的,这样处理后反而浪费性能,因为每一次浅比较也是要消耗时间的
什么是shallowEqual浅比较
这里有写得很不错的文章:浅谈React 中的浅比较是如何工作的
我总结一下这片文章里面写的东西:
- 浅比较的对象,是新旧两个props、新旧两个state
// PureReactComponent的时候进行浅对比
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
- 先判断两个对象是否地址相同。如果地址相同,就直接返回true;如果地址不相同,就继续判断
网上很多文章把第一步的意义判定为,基本类型的相等性判断
- 再判断有没有不是对象的值,或者等于null的值。如果有,直接返回false;如果没有,就继续判断
只有这一步通过了,下面的判断才有了意义
如果把第一步判定为,基本类型的判断,那第二步又如何解释呢?
话又说回来了,传进来的props或者state一定是对像啊。如果传进来的是非对象,又是怎么做到的呢?
- 再判断两个props的key数量,是否相同,如果相同就继续下一步的判断;如果不相同,就直接返回false
- 最后一步,分别判断每个key对应的value值,是否相同。判断value是否相同,使用的是object.is()
此处附上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;
}
什么是React.memo
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
},areEqual);
-
React.memo是高阶组件,
-
包裹其中的组件,并返回新的组件。该组件在props没有变更的时候,就会返回相同的渲染结果,也就是直接跳过渲染阶段。该阶段及其之后的阶段的生命周期函数就不会得到调用。当然,进行的也是浅比较
-
用法:
- 第一个参数,是函数组件( React.FunctionComponent)
- 第二个参数,回调函数。如果我们觉得浅比较不行,我们就填入第二个参数,React会把第二个参数的返回值,当作是否跳过更新的标准
function areEqual(prevProps, nextProps) {
/*
如果把 nextProps 传入 render 方法的返回结果与
将 prevProps 传入 render 方法的返回结果一致则返回 true,
否则返回 false
*/
}
- 与 class 组件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual 会返回 true;如果 props 不相等,则返回 false。这与 shouldComponentUpdate 方法的返回值相反
这个要引起我们的注意
总结
这是react为跳过子组件更新而做出的努力
- 生命周期函数 shouldComponentUpdate
- Component类,React.pureComponent
- Memo