React memo介紹與使用

前言

介紹之前可以瞭解下shouldComponentUpdateReact 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>
        )
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章