当我们组件内部有大量的计算是,避免组件内部进行不必要的重新渲染,使用React.memo进行缓存组件,避免不必要的重新渲染
React.memo
是用来判断是否需要重新渲染组件,和shouldComponentUpdate
的区别是
shouldComponentUpdate
用于class组件方式,而React.memo
用于hooks
方式
React.memo(Component, propsAreEqual)
function memo<P extends object>(
Component: FunctionComponent<P>,
propsAreEqual?: (prevProps: Readonly<PropsWithChildren<P>>, nextProps: Readonly<PropsWithChildren<P>>) => boolean
): NamedExoticComponent<P>;
function memo<T extends ComponentType<any>>(
Component: T,
propsAreEqual?: (prevProps: Readonly<ComponentProps<T>>, nextProps: Readonly<ComponentProps<T>>) => boolean
): MemoExoticComponent<T>;
默认根据props的浅比较进行来判断子组件是否更新
import React, { useState, useRef, useEffect, useMemo } from 'react';
const LiveInfo = (props) => {
return <div>
LiveInfo
</div>
}
export default React.memo(LiveInfo);
传递第二个参数是就根据第一个参数返回值判断
import React, { useState, useRef, useEffect, useMemo } from 'react';
const LiveInfo = (props) => {
return <div>
LiveInfo
</div>
}
export default React.memo(LiveInfo, function propsAreEqual(prevProps, nextProps) {
if (prevProps.visbile !== nextProps.visible) {
return false // 更新
}
return true // 复用,不重新渲染
});
是否应该更新组件,true更新、false不更新
shouldComponentUpdate(nextProps, nextState)
export default class PromiseRender extends React.Component {
state = {
component: null,
};
shouldComponentUpdate = (nextProps, nextState) => {
const { component } = this.state;
if (nextState.component !== component) return true; // 更新
return false; // 不更新
};
render() {
const { component: Component } = this.state;
const { ...rest } = this.props;
return Component ? (
<Component {...rest} />
) : (
<div
style={{
width: '100%',
height: '100%',
margin: 'auto',
paddingTop: 50,
textAlign: 'center',
}}
>
</div>
);
}
}
改写了
shouldComponentUpdate
,添加上了浅比较
而 PureComponent
也就是改写了 shouldComponentUpdate
,加上了浅比较,React源码:
if (type.prototype && type.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
shallowEqual 源码:
const hasOwn = Object.prototype.hasOwnProperty
function is(x, y) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
return x !== x && y !== y
}
}
export default function shallowEqual(objA, objB) {
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
for (let i = 0; i < keysA.length; i++) {
if (!hasOwn.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])) {
return false
}
}
return true
}