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

React前端渲染優(yōu)化--父組件導(dǎo)致子組件重復(fù)渲染的問(wèn)題

 更新時(shí)間:2022年08月04日 15:22:08   作者:DominicElvira  
本篇文章是針對(duì)父組件導(dǎo)致子組件重復(fù)渲染的優(yōu)化方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

React前端渲染優(yōu)化--父組件導(dǎo)致子組件重復(fù)渲染

說(shuō)明

目前我們所使用 react 版本一般會(huì)有以下四種方式觸發(fā)渲染 render,而其中通過(guò)父組件 render 會(huì)直接通知子組件也進(jìn)行 render。

一般的優(yōu)化方式

鑒于此種情況,如果完全不做控制下,父組件 render, 那么子組件一定會(huì) render。真實(shí) dom 的渲染 react 會(huì)在 diff 算法之后合計(jì)出最小改動(dòng),進(jìn)行操作。但對(duì)于結(jié)構(gòu)復(fù)雜頁(yè)面,自頂向下,只是單純 diff 也要花費(fèi)很長(zhǎng)的時(shí)間來(lái)處理 js 任務(wù)。再加上我們每個(gè)組件的 render 中也會(huì)寫(xiě)很多業(yè)務(wù)、數(shù)據(jù)處理。

js 為單線程執(zhí)行,顯然,不必要的子組件的 render 會(huì)浪費(fèi) js 線程資源,復(fù)雜任務(wù)還會(huì)長(zhǎng)時(shí)間占用線程導(dǎo)致假死狀態(tài),也就是頁(yè)面卡頓,react 底層有 Fiber 來(lái)優(yōu)化任務(wù)隊(duì)列,但無(wú)法優(yōu)化業(yè)務(wù)代碼上的問(wèn)題。

一般子組件可以通過(guò)確認(rèn) props 是否發(fā)生變化來(lái)控制自身是否進(jìn)行 render,比如 react-mobx 中的 observer 高階方法或者 React.PureComponet 就是用來(lái)做淺層比較進(jìn)行控制處理。

項(xiàng)目中常見(jiàn)會(huì)導(dǎo)致重復(fù)渲染的寫(xiě)法以及改進(jìn)方法

函數(shù)導(dǎo)致的渲染重復(fù)

箭頭函數(shù) props.fn = () => {} 或者 綁定方法 props.fn = this.xxx.bind(this)

這樣的寫(xiě)法每次父組件 render 都會(huì)新聲明一個(gè) function 傳遞給子組件,會(huì)導(dǎo)致 observer 失去比對(duì)作用,父組件每次 render 都會(huì)使這個(gè)組件 render,嚴(yán)重影響性能!

import React from 'react';
import { observer } from 'mobx-react';
// 我們開(kāi)發(fā)中常見(jiàn)的一個(gè)被觀測(cè)組件,例如 ObserverComponent
@observer
class ObserverComponent extends React.Component {
    render() {
        return (<div>ObserverComponent</div>)
    }
}
// 例如在父組件 Parent 使用被觀測(cè)的子組件 ObserverComponent
// 請(qǐng)不要給子組件 ObserverComponent 的 props 設(shè)置 箭頭函數(shù) () => {} 或者 fn.bind(this) 方法
@observer
class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this); // 【正確】
    }
    handleChange() {}
    doSomething = () => {}
    render() {
        return (
            <ObserverComponent
                onChange={() => {}}                      // 【錯(cuò)誤】
                onChange={this.handleChange.bind(this)}  // 【錯(cuò)誤】
                onChange={this.handleChange}             // 【正確】
                todo={this.doSomething}                  // 【正確】
            />
        )
    }
}

字面量寫(xiě)法導(dǎo)致的渲染重復(fù)

由于字面量的寫(xiě)法{} 和 { pageSizeOptions: ['10'] },每次都會(huì)字面量聲明一個(gè)新的對(duì)象傳遞給列表組件,導(dǎo)致頁(yè)面重新 render。

toJS() 方法每次也會(huì)返回新對(duì)象,會(huì)導(dǎo)致頁(yè)面重新渲染

組件重復(fù)渲染問(wèn)題(pureComponent, React.memo, useMemo, useCallback)

在一個(gè)組件中, 其state變化會(huì)引起render的重新執(zhí)行, 函數(shù)式組件中, 使用setHook更新state也會(huì)引起render的重新執(zhí)行

render執(zhí)行會(huì)帶來(lái)兩個(gè)方面的影響

  • 1.當(dāng)前組件需要重新渲染, 除了那些狀態(tài)和生命周期初始化被保留的,其余正常的都會(huì)重新執(zhí)行。
  • 2.子組件會(huì)重新渲染, 即使其是一個(gè)無(wú)狀態(tài)組件

針對(duì)上述問(wèn)題, react給出來(lái)解決方案:

  • pureComponent
  • React.memo
  • useMemo
  • useCallback

下面將具體說(shuō)明這幾個(gè)都使用場(chǎng)景和解決的問(wèn)題

  • useMemo設(shè)計(jì)的初衷就是避免重復(fù)進(jìn)行大規(guī)模的計(jì)算, 它的理想作用對(duì)象是當(dāng)前組件

具體是將當(dāng)前組件中一個(gè)經(jīng)過(guò)很復(fù)雜的計(jì)算得到的值緩存起來(lái), 當(dāng)其依賴項(xiàng)不變的時(shí)候, 即使組件重新渲染, 也不會(huì)重新計(jì)算。

通過(guò)上述描述也能理解出其緩存的是一個(gè)具體的數(shù)據(jù)(可以和接下來(lái)的useCallback區(qū)分開(kāi))

/*
緩存了一個(gè)對(duì)象, 只有當(dāng)count變化時(shí)才會(huì)重新返回該對(duì)象
*/
const useInfo = useMemo(
    () => ({
        count: count,
        name: "name"
    }),
    [count]
)
  • 針對(duì)第二點(diǎn), 分別有三個(gè)解決方案

首先是useCallback, 其語(yǔ)法和useMemo基本一致, 但是其使用場(chǎng)景是父組件定義了一個(gè)函數(shù)并且將這個(gè)函數(shù)傳遞給了子組件, 那么當(dāng)父組件重新渲染時(shí),生成的會(huì)是一個(gè)新的函數(shù), 這個(gè)時(shí)候就可以使用useCallback了,如下:

const Page = (props) => {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('Child組件');
    return (
        <>
            <ChildMemo name={name} onClick={ useCallback((newName: string) => setName(newName), []) }/>
            {/* useCallback((newName: string) => setName(newName),[]) */}
            {/* 這里使用了useCallback優(yōu)化了傳遞給子組件的函數(shù),只初始化一次這個(gè)函數(shù),下次不產(chǎn)生新的函數(shù)
        </>
    )
}

上述是一個(gè)簡(jiǎn)寫(xiě)的形式,意思就是將傳遞給子組件的這個(gè)函數(shù)緩存了,其第二個(gè)參數(shù)就是依賴,當(dāng)該依賴變化時(shí),將會(huì)重新緩存該函數(shù)

其余useMemo的區(qū)別就在于,其緩存的是函數(shù)本身,而useMemo緩存的是函數(shù)計(jì)算后的值,都會(huì)在依賴項(xiàng)變化時(shí)重新緩存。

注:雖然其可能對(duì)于父組件傳遞給子組件函數(shù)時(shí)可能很理想,但實(shí)際上其帶來(lái)的性能損耗也是顯而易見(jiàn)的,其使用場(chǎng)景不應(yīng)該是擔(dān)心本組件的函數(shù)因?yàn)楸窘M件重新渲染而重新生成,這樣反而起到了反效果,當(dāng)前組件更新,其重新渲染,內(nèi)部的函數(shù)也重新生成,其性能損耗可以忽略不計(jì),如下圖。

使用場(chǎng)景應(yīng)該是父組件更新導(dǎo)致重新生成的函數(shù)又傳遞給了子組件,導(dǎo)致子組件重新渲染。

  • 接著是pureComponent

它是一個(gè)類(lèi), 組件繼承自它后, 其作為子組件時(shí), 每次父組件更新后, 會(huì)淺對(duì)比傳來(lái)的props是否變化, 若沒(méi)變化, 則子組件不更新。

  • React.memo

同上條功能類(lèi)似, 當(dāng)其作用于函數(shù)式組件并且作為子組件時(shí), 每次父組件更新后, 會(huì)淺對(duì)比傳來(lái)的props是否變化, 若沒(méi)變化, 則子組件不更新。

// 子組件暴露時(shí)暴露為處理后的組件
import {memo} from 'react'
const TeacherModal = (props: any) => {
  return <div></div>
}
export default memo(TeacherModal)

上面兩個(gè)都區(qū)別在于, 一個(gè)是類(lèi), 一個(gè)是高階組件, 前者作用于類(lèi)后者作用于函數(shù)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 利用CDN加速react webpack打包后的文件詳解

    利用CDN加速react webpack打包后的文件詳解

    下面小編就為大家分享一篇利用CDN加速react webpack打包后的文件詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • react native 原生模塊橋接的簡(jiǎn)單說(shuō)明小結(jié)

    react native 原生模塊橋接的簡(jiǎn)單說(shuō)明小結(jié)

    這篇文章主要介紹了react native 原生模塊橋接的簡(jiǎn)單說(shuō)明小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • antd-react使用Select組件defaultValue踩的坑及解決

    antd-react使用Select組件defaultValue踩的坑及解決

    這篇文章主要介紹了antd-react使用Select組件defaultValue踩的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 詳解React 服務(wù)端渲染方案完美的解決方案

    詳解React 服務(wù)端渲染方案完美的解決方案

    這篇文章主要介紹了詳解React 服務(wù)端渲染方案完美的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • react結(jié)合bootstrap實(shí)現(xiàn)評(píng)論功能

    react結(jié)合bootstrap實(shí)現(xiàn)評(píng)論功能

    這篇文章主要為大家詳細(xì)介紹了react結(jié)合bootstrap實(shí)現(xiàn)評(píng)論功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • react中的虛擬dom和diff算法詳解

    react中的虛擬dom和diff算法詳解

    這篇文章主要介紹了react中的虛擬dom和diff算法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • React實(shí)現(xiàn)點(diǎn)擊刪除列表中對(duì)應(yīng)項(xiàng)

    React實(shí)現(xiàn)點(diǎn)擊刪除列表中對(duì)應(yīng)項(xiàng)

    本文主要介紹了React 點(diǎn)擊刪除列表中對(duì)應(yīng)項(xiàng)的方法。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • React可定制黑暗模式切換開(kāi)關(guān)組件

    React可定制黑暗模式切換開(kāi)關(guān)組件

    這篇文章主要為大家介紹了React可定制黑暗模式切換開(kāi)關(guān)組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • React-View-UI組件庫(kù)封裝Loading加載中源碼

    React-View-UI組件庫(kù)封裝Loading加載中源碼

    這篇文章主要介紹了React-View-UI組件庫(kù)封裝Loading加載樣式,主要包括組件介紹,組件源碼及組件測(cè)試源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • React-Route6實(shí)現(xiàn)keep-alive效果

    React-Route6實(shí)現(xiàn)keep-alive效果

    本文主要介紹了React-Route6實(shí)現(xiàn)keep-alive效果,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>
    2022-06-06

最新評(píng)論