介绍之前可以了解下shouldComponentUpdate,React PureComponent。
React.memo 为高阶组件。它与 React.PureComponent 非常相似,但它适用于函数组件,但不适用于 class 组件。
如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。
const MyComponent = React.memo(function MyComponent(props) {
/* 只在props更改的时候才会重新渲染 */
});
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
function MyComponent(props) {
/* render using props */
}
export default React.memo(MyComponent, areEqual);
例子:
import React from "react";
function Child({seconds}){
console.log('I am rendering');
return (
<div>I am update every {seconds} seconds</div>
)
};
function areEqual(prevProps, nextProps) {
if(prevProps.seconds===nextProps.seconds){
return true
}else {
return false
}
}
export default React.memo(Child,areEqual)
其实react.memo的实现很简单,如下:
export default function memo<Props>(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
if (__DEV__) {
if (!isValidElementType(type)) {
warningWithoutStack(
false,
'memo: The first argument must be a component. Instead ' +
'received: %s',
type === null ? 'null' : typeof type,
);
}
}
return {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
}
可以看到,最终返回的是一个对象,这个对象带有一些标志属性,在react Fiber的过程中会做相应的处理。
在ReactFiberBeginWork.js中可以看到:
if (updateExpirationTime < renderExpirationTime) {
// This will be the props with resolved defaultProps,
// unlike current.memoizedProps which will be the unresolved ones.
const prevProps = currentChild.memoizedProps;
// Default to shallow comparison
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
}
根据传入的compare函数比较prevProps和nextProps,最终决定生成对象,并影响渲染效果。
其实就是在实现shouldComponentUpdate生命周期,之前的PureComponent是在class组件中使用,现在的memo是让函数式组件可以实现相同效果。
React.memo()使用场景就是纯函数组件频繁渲染props
import React, { Component } from 'react'
// 使用React.memo代替以上的title组件,让函数式组件也拥有Purecomponent的功能
const Title=React.memo((props)=>{
console.log("我是title组件")
return (
<div>
标题: {props.title}
</div>
)
})
class Count extends Component {
render() {
console.log("我是条数组件")
return (
<div>
条数:{this.props.count}
</div>
)
}
}
export default class Purememo extends Component {
constructor(props){
super(props)
this.state={
title:'shouldComponentUpdate使用',
count:0
}
}
componentDidMount(){
setInterval(()=>{
this.setState({
count:this.state.count+1
})
},1000)
}
render() {
return (
<div>
<Title title={this.state.title}></Title>
<Count count={this.state.count}></Count>
</div>
)
}
}