前言
介紹之前可以瞭解下shouldComponentUpdate,React PureComponent。
React.memo介紹
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原理
其實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使用(適用函數式組件)
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>
)
}
}