欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解使用React.memo()來優(yōu)化函數(shù)組件的性能

 更新時(shí)間:2019年03月19日 09:19:06   投稿:zx  
本文講述了開發(fā)React應(yīng)用時(shí)如何使用shouldComponentUpdate生命周期函數(shù)以及PureComponent去避免類組件進(jìn)行無用的重渲染,以及如何使用最新的React.memo API去優(yōu)化函數(shù)組件的性能

React核心開發(fā)團(tuán)隊(duì)一直都努力地讓React變得更快。在React中可以用來優(yōu)化組件性能的方法大概有以下幾種:

  • 組件懶加載(React.lazy(...)和<Suspense />)
  • Pure Component
  • shouldComponentUpdate(...){...}生命周期函數(shù)

本文還會(huì)介紹React16.6加入的另外一個(gè)專門用來優(yōu)化函數(shù)組件(Functional Component)性能的方法: React.memo。

無用的渲染

組件是構(gòu)成React視圖的一個(gè)基本單元。有些組件會(huì)有自己本地的狀態(tài)(state), 當(dāng)它們的值由于用戶的操作而發(fā)生改變時(shí),組件就會(huì)重新渲染。在一個(gè)React應(yīng)用中,一個(gè)組件可能會(huì)被頻繁地進(jìn)行渲染。這些渲染雖然有一小部分是必須的,不過大多數(shù)都是無用的,它們的存在會(huì)大大降低我們應(yīng)用的性能。

看下面這個(gè)例子:

import React from 'react';

class TestC extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  
  componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate')
  }
  
  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate')
    
  }
  
  render() {
    return (
      <div >
      {this.state.count}
      <button onClick={()=>this.setState({count: 1})}>Click Me</button>
      </div>
    );
  }
}
export default TestC;

TestC組件有一個(gè)本地狀態(tài)count,它的初始值是0(state = {count: 0})。當(dāng)我們點(diǎn)擊Click Me按鈕時(shí),count的值被設(shè)置為1。這時(shí)候屏幕的數(shù)字將會(huì)由0變成1。當(dāng)我們?cè)俅吸c(diǎn)擊該按鈕時(shí),count的值還是1, 這時(shí)候TestC組件不應(yīng)該被重新渲染,可是現(xiàn)實(shí)是這樣的嗎?

為了測(cè)試count重復(fù)設(shè)置相同的值組件會(huì)不會(huì)被重新渲染, 我為TestC組件添加了兩個(gè)生命周期函數(shù): componentWillUpdate和componentDidUpdate。componentWillUpdate方法在組件將要被重新渲染時(shí)被調(diào)用,而componentDidUpdate方法會(huì)在組件成功重渲染后被調(diào)用。

在瀏覽器中運(yùn)行我們的代碼,然后多次點(diǎn)擊Click Me按鈕,你可以看到以下輸出:


我們可以看到'componentWillUpdate'和'componentWillUpdate'在每次我們點(diǎn)擊完按鈕后,都會(huì)在控制臺(tái)輸出來。所以即使count被設(shè)置相同的值,TestC組件還是會(huì)被重新渲染,這些就是所謂的無用渲染。

Pure Component/shouldComponentUpdate

為了避免React組件的無用渲染,我們可以實(shí)現(xiàn)自己的shouldComponentUpdate生命周期函數(shù)。

當(dāng)React想要渲染一個(gè)組件的時(shí)候,它將會(huì)調(diào)用這個(gè)組件的shouldComponentUpdate函數(shù), 這個(gè)函數(shù)會(huì)告訴它是不是真的要渲染這個(gè)組件。

如果我們的shouldComponentUpdate函數(shù)這樣寫:

shouldComponentUpdate(nextProps, nextState) {
  return true    
}

其中各個(gè)參數(shù)的含義是:

  • nextProps: 組件將會(huì)接收的下一個(gè)參數(shù)props
  • nextProps: 組件的下一個(gè)狀態(tài)state

因?yàn)槲覀兊膕houldComponentUpdate函數(shù)一直返回true,這就告訴React,無論何種情況都要重新渲染該組件。

可是如果我們這么寫:

shouldComponentUpdate(nextProps, nextState) {
  return false
}

因?yàn)檫@個(gè)方法的返回值是false,所以React永遠(yuǎn)都不會(huì)重新渲染我們的組件。

因此當(dāng)你想要React重新渲染你的組件的時(shí)候,就在這個(gè)方法中返回true,否則返回false。現(xiàn)在讓我們用shouldComponentUpdate重寫之前的TestC組件:

import React from 'react';

class TestC extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  
  componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate')
  }
  
  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate')
  }
  
  shouldComponentUpdate(nextProps, nextState) {
    if (this.state.count === nextState.count) {
      return false
    }
    return true
  }
  
  render() {
    return ( 
      <div> 
      { this.state.count } 
      <button onClick = {
        () => this.setState({ count: 1 }) }> Click Me </button> 
      </div>
    );
  }
}

export default TestC;

我們?cè)赥estC組件里添加了shouldComponentUpdate方法,判斷如果現(xiàn)在狀態(tài)的count和下一個(gè)狀態(tài)的count一樣時(shí),我們返回false,這樣React將不會(huì)進(jìn)行組件的重新渲染,反之,如果它們兩個(gè)的值不一樣,就返回true,這樣組件將會(huì)重新進(jìn)行渲染。

再次在瀏覽器中測(cè)試我們的組件,剛開始的界面是這樣的:

這時(shí)候,就算我們多次點(diǎn)擊Click Me按鈕,也只能看到兩行輸出:

componentWillUpdate
componentDidUpdate

因?yàn)榈诙吸c(diǎn)擊Click Me按鈕后count值一直是1,這樣shouldComponentUpdate一直返回false,所以組件就不再被重新渲染了。

那么如何驗(yàn)證后面state的值發(fā)生改變,組件還是會(huì)被重新渲染呢?我們可以在瀏覽器的React DevTools插件中直接對(duì)TestC組件的狀態(tài)進(jìn)行更改。具體做法是, 在Chrome調(diào)試工具中點(diǎn)擊React標(biāo)簽,在界面左邊選中TestC組件,在界面的右邊就可以看到其狀態(tài)state中只有一個(gè)鍵count,且其值是1:


然后讓我們點(diǎn)擊count的值1,將其修改為2,然后按回車鍵:


你將會(huì)看到控制臺(tái)有以下輸出:

componentWillUpdate
componentDidUpdate
componentWillUpdate
componentDidUpdate

state的count被改變了,組件也被重新渲染了。

現(xiàn)在讓我們使用另外一種方法PureComponent來對(duì)組件進(jìn)行優(yōu)化。

React在v15.5的時(shí)候引入了Pure Component組件。React在進(jìn)行組件更新時(shí),如果發(fā)現(xiàn)這個(gè)組件是一個(gè)PureComponent,它會(huì)將組件現(xiàn)在的state和props和其下一個(gè)state和props進(jìn)行淺比較,如果它們的值沒有變化,就不會(huì)進(jìn)行更新。要想讓你的組件成為Pure Component,只需要extends React.PureComponent即可。

讓我們用PureComponent去改寫一下我們的代碼吧:

import React from 'react';

class TestC extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  
  componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate')
  }
  
  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate')
  }
  
  /*shouldComponentUpdate(nextProps, nextState) {
    if (this.state.count === nextState.count) {
      return false
    }
    return true
  }*/
  
  render() {
    return ( 
      <div> 
      { this.state.count } 
      <button onClick = {
        () => this.setState({ count: 1 })
      }> Click Me </button> 
      </div >
    );
  }
}

export default TestC;

在上面的代碼中,我將shouldComponentUpdate的代碼注釋掉了,因?yàn)镽eact.PureComponent本身就幫我們實(shí)現(xiàn)了一樣的功能。

改完代碼后,我們刷新一下瀏覽器,然后多次點(diǎn)擊Click Me按鈕看組件被渲染了多少遍:


由上面的輸出可知,我們的component只在state由0變?yōu)?時(shí)被重新渲染了,后面都沒有進(jìn)行渲染。

函數(shù)組件

上面我們探討了如何使用PureComponentshouldComponentUpdate的方法優(yōu)化類組件的性能。雖然類組件是React應(yīng)用的主要組成部分,不過函數(shù)組件(Functional Component)同樣可以被作為React組件使用。

function TestC(props) {
  return (
    <div>
      I am a functional component
    </div>
  )
}

對(duì)于函數(shù)組件,它們沒有諸如state的東西去保存它們本地的狀態(tài)(雖然在React Hooks中函數(shù)組件可以使用useState去使用狀態(tài)), 所以我們不能像在類組件中使用shouldComponentUpdate等生命函數(shù)去控制函數(shù)組件的重渲染。當(dāng)然,我們也不能使用extends React.PureComponent了,因?yàn)樗鼔焊筒皇且粋€(gè)類。

要探討解決方案,讓我們先驗(yàn)證一下函數(shù)組件是不是也有和類組件一樣的無用渲染的問題。

首先我們先將ES6的TestC類轉(zhuǎn)換為一個(gè)函數(shù)組件:

import React from 'react';

const TestC = (props) => {
  console.log(`Rendering TestC :` props)
  return ( 
    <div>
      {props.count}
    </div>
  )
}
export default TestC;
// App.js
<TestC count={5} />

當(dāng)上面的代碼初次加載時(shí),控制臺(tái)的輸出是:


同樣,我們可以打開Chrome的調(diào)試工具,點(diǎn)擊React標(biāo)簽然后選中TestC組件:


我們可以看到這個(gè)組件的參數(shù)值是5,讓我們將這個(gè)值改為45, 這時(shí)候?yàn)g覽器輸出:


由于count的值改變了,所以該組件也被重新渲染了,控制臺(tái)輸出Object{count: 45},讓我們重復(fù)設(shè)置count的值為45, 然后再看一下控制臺(tái)的輸出結(jié)果:


由輸出結(jié)果可以看出,即使count的值保持不變,還是45, 該組件還是被重渲染了。

既然函數(shù)組件也有無用渲染的問題,我們?nèi)绾螌?duì)其進(jìn)行優(yōu)化呢?

解決方案: 使用React.memo()

React.memo(...)是React v16.6引進(jìn)來的新屬性。它的作用和React.PureComponent類似,是用來控制函數(shù)組件的重新渲染的。React.memo(...) 其實(shí)就是函數(shù)組件的React.PureComponent

如何使用React.memo(...)?

React.memo使用起來非常簡單,假設(shè)你有以下的函數(shù)組件:

const Funcomponent = ()=> {
  return (
    <div>
      Hiya!! I am a Funtional component
    </div>
  )
}

我們只需將上面的Funcomponent作為參數(shù)傳入React.memo中:

const Funcomponent = ()=> {
  return (
    <div>
      Hiya!! I am a Funtional component
    </div>
  )
}
const MemodFuncComponent = React.memo(FunComponent)

React.memo會(huì)返回一個(gè)純化(purified)的組件MemoFuncComponent,這個(gè)組件將會(huì)在JSX標(biāo)記中渲染出來。當(dāng)組件的參數(shù)props和狀態(tài)state發(fā)生改變時(shí),React將會(huì)檢查前一個(gè)狀態(tài)和參數(shù)是否和下一個(gè)狀態(tài)和參數(shù)是否相同,如果相同,組件將不會(huì)被渲染,如果不同,組件將會(huì)被重新渲染。

現(xiàn)在讓我們?cè)赥estC組件上使用React.memo進(jìn)行優(yōu)化:

let TestC = (props) => {
  console.log('Rendering TestC :', props)
  return ( 
    <div>
    { props.count }
    </>
  )
}
TestC = React.memo(TestC);

打開瀏覽器重新加載我們的應(yīng)用。然后打開Chrome調(diào)試工具,點(diǎn)擊React標(biāo)簽,然后選中<Memo(TestC)>組件。

接著編輯一下props的值,將count改為89,我們將會(huì)看到我們的應(yīng)用被重新渲染了:


然后重復(fù)設(shè)置count的值為89:


這里沒有重新渲染!

這就是React.memo(...)這個(gè)函數(shù)牛X的地方!

在我們之前那個(gè)沒用到React.memo(...)的例子中,count的重復(fù)設(shè)置會(huì)使組件進(jìn)行重新渲染??墒俏覀冇昧薘eact.memo后,該組件在傳入的值不變的前提下是不會(huì)被重新渲染的。

結(jié)論

以下是幾點(diǎn)總結(jié):

  • React.PureComponent是銀
  • React.memo(...)是金
  • React.PureComponent是給ES6的類組件使用的
  • React.memo(...)是給函數(shù)組件使用的
  • React.PureComponent減少ES6的類組件的無用渲染
  • React.memo(...)減少函數(shù)組件的無用渲染
  • 為函數(shù)組件提供優(yōu)化是一個(gè)巨大的進(jìn)步

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • react ant-design Select組件下拉框map不顯示的解決

    react ant-design Select組件下拉框map不顯示的解決

    這篇文章主要介紹了react ant-design Select組件下拉框map不顯示的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Ant Design中使用css切換的問題及解決

    Ant Design中使用css切換的問題及解決

    這篇文章主要介紹了Ant Design中使用css切換的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 高性能React開發(fā)React Server Components詳解

    高性能React開發(fā)React Server Components詳解

    ReactServerComponents通過服務(wù)器端渲染、自動(dòng)代碼分割等技術(shù),實(shí)現(xiàn)了高性能的React開發(fā),它解決了客戶端數(shù)據(jù)請(qǐng)求鏈?zhǔn)窖舆t、敏感數(shù)據(jù)暴露風(fēng)險(xiǎn)等問題,提供了更好的用戶體驗(yàn)和安全性,本文介紹高性能React開發(fā)React Server Components詳解,感興趣的朋友一起看看吧
    2025-03-03
  • React實(shí)現(xiàn)基于Antd密碼強(qiáng)度校驗(yàn)組件示例詳解

    React實(shí)現(xiàn)基于Antd密碼強(qiáng)度校驗(yàn)組件示例詳解

    這篇文章主要為大家介紹了React實(shí)現(xiàn)基于Antd密碼強(qiáng)度校驗(yàn)組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 淺談React中組件間抽象

    淺談React中組件間抽象

    這篇文章主要介紹了淺談React中組件間抽象,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • 官方推薦react-navigation的具體使用詳解

    官方推薦react-navigation的具體使用詳解

    本篇文章主要介紹了官方推薦react-navigation的具體使用詳解,react-navigation是致力于解決導(dǎo)航卡頓,數(shù)據(jù)傳遞,Tabbar和navigator布局,支持redux。非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-05-05
  • React組件通信實(shí)現(xiàn)流程詳解

    React組件通信實(shí)現(xiàn)流程詳解

    這篇文章主要介紹了React組件通信,在開發(fā)中組件通信是React中的一個(gè)重要的知識(shí)點(diǎn),本文通過實(shí)例代碼給大家講解react中常用的父子、跨組件通信的方法,需要的朋友可以參考下
    2022-12-12
  • 解決React在安裝antd之后出現(xiàn)的Can''t resolve ''./locale''問題(推薦)

    解決React在安裝antd之后出現(xiàn)的Can''t resolve ''./locale''問題(推薦)

    這篇文章主要介紹了解決React在安裝antd之后出現(xiàn)的Can't resolve './locale'問題,本文給大家分享解決方案,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 解決React報(bào)錯(cuò)useNavigate()?may?be?used?only?in?context?of?Router

    解決React報(bào)錯(cuò)useNavigate()?may?be?used?only?in?context?of

    這篇文章主要為大家介紹了解決React報(bào)錯(cuò)useNavigate()?may?be?used?only?in?context?of?Router,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React渲染機(jī)制超詳細(xì)講解

    React渲染機(jī)制超詳細(xì)講解

    React整個(gè)的渲染機(jī)制就是React會(huì)調(diào)用render()函數(shù)構(gòu)建一棵Dom樹,在state/props發(fā)生改變的時(shí)候,render()函數(shù)會(huì)被再次調(diào)用渲染出另外一棵樹,重新渲染所有的節(jié)點(diǎn),構(gòu)造出新的虛擬Dom tree
    2022-11-11

最新評(píng)論