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

React重新渲染超詳細(xì)講解

 更新時(shí)間:2022年11月25日 15:58:12   作者:何遇er  
什么是re-render(重新渲染)?哪些是必要的re-render?哪些是非必要的re-render?如果你對(duì)這些問(wèn)題還不是很明白,那么可以在這篇文章中找到答案

Web 前端開發(fā)者對(duì)渲染和重新渲染應(yīng)該不陌生,在 React 中,它們究竟是什么意思?

  • 渲染:React 讓組件根據(jù)當(dāng)前的 props 和 state 描述它要展示的內(nèi)容。
  • 重新渲染:React 讓組件重新描述它要展示的內(nèi)容。

要將組件顯示到屏幕上,React 的工作主要分為兩個(gè)階段,本文介紹與 React 渲染相關(guān)的知識(shí)。

  • render 階段(渲染階段):計(jì)算組件的輸出并收集所有需要應(yīng)用到 DOM 上的變更。
  • commit 階段(提交階段):將 render 階段計(jì)算出的變更應(yīng)用到 DOM 上。

在 commit 階段 React 會(huì)更新 DOM 節(jié)點(diǎn)和組件實(shí)例的 ref,如果是類組件,React會(huì)同步運(yùn)行 componentDidMount 或 componentDidUpdate 生命周期方法,如果是函數(shù)組件,React會(huì)同步運(yùn)行 useLayoutEffect 勾子,當(dāng)瀏覽器繪制 DOM 之后,再運(yùn)行所有的 useEffect 勾子。

React 重新渲染

初始化渲染之后,下面的這些原因會(huì)讓React重新渲染組件:

類組件

  • 調(diào)用 this.setState 方法。
  • 調(diào)用this.forceUpdate方法。

函數(shù)組件

  • 調(diào)用 useState 返回的 setState。
  • 調(diào)用 useReducer 返回的 dispatch。

其他

  • 組件訂閱的 context value 發(fā)生變更
  • 重新調(diào)用 ReactDOM.render(<AppRoot>)

假設(shè)組件樹如下

默認(rèn)情況,如果父組件重新渲染,那么 React 會(huì)重新渲染它所有的子組件。當(dāng)用戶點(diǎn)擊組件 A 中的按鈕,使 A 組件 count 狀態(tài)值加1,將發(fā)生如下的渲染流程:

  • React將組件A添加到重新渲染隊(duì)列中。
  • 從組件樹的頂部開始遍歷,快速跳過(guò)不需要更新的組件。
  • React發(fā)生A組件需要更新,它會(huì)渲染A。A返回B和C
  • B沒(méi)有被標(biāo)記為需要更新,但由于它的父組件A被渲染了,所以React會(huì)渲染B
  • C沒(méi)有被標(biāo)記為需要更新,但由于它的父組件A被渲染了,所以React會(huì)渲染C,C返回D
  • D沒(méi)有標(biāo)記為需要更新,但由于它的父組件C被渲染了,所以D會(huì)被渲染。

在默認(rèn)渲染流程中,React 不關(guān)心子組件的 props 是否改變了,它會(huì)無(wú)條件地渲染子組件。很可能上圖中大多數(shù)組件會(huì)返回與上次完全相同的結(jié)果,因此 React 不需要對(duì)DOM 做任何更改,但是,React 仍然會(huì)要求組件渲染自己并對(duì)比前后兩次渲染輸出的結(jié)果,這兩者都需要時(shí)間。

Reconciliation

Reconciliation 被稱為 diff 算法,它用來(lái)比較兩顆 React 元素樹之間的差異,為了讓組件重新渲染變得高效,React 盡可能地復(fù)用現(xiàn)有的組件和 DOM。為了降低時(shí)間復(fù)雜度,Diff 算法基于如下兩個(gè)假設(shè):

  • 兩個(gè)不同類型的元素對(duì)應(yīng)的元素樹完全不同。
  • 在同一個(gè)列表中,如果兩個(gè)元素key屬性的值相同,那么它們被識(shí)別為同一個(gè)元素。

元素類型對(duì) Diff 的影響

React 使用元素的 type 字段比較元素類型是否相同,如果兩顆樹在相同位置要渲染的元素類型相同,那么 React 就重用這些元素,并在適當(dāng)?shù)臅r(shí)候更新,不需要重新創(chuàng)建元素,這意味著,只要一直要求 React 將某組件渲染在相同的位置,那么 React 始終不會(huì)卸載該組件。如果相同位置的元素類型不同,例如從 div 到 span 或者從ComponentA 到 ComponentB,React會(huì)認(rèn)為整個(gè)樹發(fā)生了變化,為了加快比較過(guò)程,React 會(huì)銷毀整個(gè)現(xiàn)有的組件樹,包括所有的 DOM 節(jié)點(diǎn),然后重新創(chuàng)建元素。

瀏覽器內(nèi)置元素的 type 字段是一個(gè)字符串,自定義組件元素的 type 字段是一個(gè)類或者函數(shù),由于元素類型對(duì) Diff的影響,所以在渲染期間不要?jiǎng)?chuàng)建組件,只要?jiǎng)?chuàng)建一個(gè)新的組件,那么它的 type 字段就是不同的引用,這將導(dǎo)致 React 不斷地銷毀并重新創(chuàng)建子組件樹。不要有如下的代碼:

function ParentCom() {
  // 每一次渲染 ParentCom 時(shí),都會(huì)創(chuàng)建新的ChildCom組件
  function ChildCom() {/**do something*/}
  return <ChildCom />
}

上述代碼不推薦,正確的做法是將 ChildCom 放在ParentCom 的外面。

key 對(duì) Diff 的影響

React 識(shí)別元素的另一種方式是通過(guò) key 屬性,key 作為組件的唯一標(biāo)識(shí)符不會(huì)當(dāng)作prop傳遞到組件中,可以給任何組件添加一個(gè) key 屬性來(lái)標(biāo)注它,更改 key 的值會(huì)導(dǎo)致舊的組件實(shí)例和 DOM 被銷毀。

列表是使用 key 屬性的主要場(chǎng)景,在 React 官方文檔中提到,不要將數(shù)組的下標(biāo)作為 key 值,而是用數(shù)據(jù)唯一 ID 作為 key 值。在這里分別介紹這兩種方式的區(qū)別。

假如 Todo List 中有 10 項(xiàng),先用數(shù)組下標(biāo)作為 key 的值,這 10 項(xiàng) Todo 的 key 值為 0...9,現(xiàn)在刪除數(shù)組的第 6 項(xiàng)和第 7 項(xiàng),并在數(shù)組末尾添加 3 個(gè)新的數(shù)據(jù)項(xiàng),我們最終將得到 key 值為0..10的 Todo,看起來(lái)只是在末尾新增 1 項(xiàng),將原來(lái)的列表從10項(xiàng)變成了11項(xiàng),React 很樂(lè)意復(fù)用已有的 DOM 節(jié)點(diǎn)和組件實(shí)例,這意味著原來(lái) #6 對(duì)應(yīng)的組件實(shí)例沒(méi)有被銷毀,現(xiàn)在它接收新的 props 用于呈現(xiàn)原來(lái)的 #8。在這個(gè)例子中 React 會(huì)創(chuàng)建 1 個(gè)Todo,更新 4 個(gè)Todo。

如果使用數(shù)據(jù)的 ID 作為 key 值,React 能發(fā)現(xiàn)第 6 項(xiàng)和第 7 項(xiàng)被刪除了,它也能發(fā)現(xiàn)數(shù)組新增了 3 項(xiàng),所以 React 會(huì)銷毀 #6 和 #7 項(xiàng)對(duì)應(yīng)的組件實(shí)例及其關(guān)聯(lián)的 DOM,還會(huì)創(chuàng)建 3 個(gè)組件實(shí)例及其關(guān)聯(lián)的 DOM。

提高渲染性能

要將組件顯示在界面上,組件必須經(jīng)歷渲染流程,但渲染工作有時(shí)候會(huì)被認(rèn)為是浪費(fèi)時(shí)間,如果渲染的輸出結(jié)果沒(méi)有改變,它對(duì)應(yīng)的DOM節(jié)點(diǎn)也不需要更新,此時(shí)與該組件相關(guān)的渲染工作真的是在浪費(fèi)時(shí)間。React組件的輸出結(jié)果始終基于當(dāng)前 props 和 state 的值,因此,如果我們知道組件的 props 和 state 沒(méi)有改變,那么我們可以無(wú)后顧之憂地讓組件跳過(guò)重新渲染。

跳過(guò)重新渲染

React 提供了 3 個(gè)主要的API讓我們跳過(guò)重新渲染:

  • React.Component 的 shouldComponentUpdate:這是類組件可選的生命周期函數(shù),它在組件 render 階段早期被調(diào)用,如果返回false,React 將跳過(guò)重新渲染該組件,使用它最常見的場(chǎng)景是檢查組件的 props 和 state 是否自上次以來(lái)發(fā)生了變更,如果沒(méi)有改變則返回false。
  • React.PureComponent:它在 React.Component 的基礎(chǔ)上添加默認(rèn)的 shouldComponentUpdate 去比較組件的 props 和 state 自上次渲染以來(lái)是否有變更。
  • React.memo():它是一個(gè)高階組件,接收自定義組件作為參數(shù),返回一個(gè)被包裹的組件,被包裹的組件的默認(rèn)行為是檢查 props 是否有更改,如果沒(méi)有,則跳過(guò)重新渲染。

上述方法都通過(guò)‘淺比較’來(lái)確定值是否有變更,如果通過(guò) mutable 的方式修改狀態(tài),這些 API 會(huì)認(rèn)為狀態(tài)沒(méi)有變。

  • 如果組件在其渲染過(guò)程中返回的元素的引用與上一次渲染時(shí)的引用完全相同,那么 React 不會(huì)重新渲染引用相同的組件。示例如下:
function ShowChildren(props: {children: React.ReactNode}) {
    const [count, setCount] = useState<number>(0)
    return (
        <div>
            {count} <button onClick={() => setCount(c => c + 1)}>click</button>
            {/* 寫法一 */}
            {props.children}
            {/* 寫法二 */}
            {/* <Children/> */}
        </div>
    )
}

上述 ShowChildren 的 props.children 對(duì)應(yīng) Children 組件,因此寫法一和寫法二在瀏覽器中呈現(xiàn)一樣。點(diǎn)擊按鈕不會(huì)讓寫法一的 Children 組件重新渲染,但是會(huì)使寫法二的 Children 組件重新渲染。

上述4種方式跳過(guò)重新渲染意味著 React 會(huì)跳過(guò)整個(gè)子樹的重新渲染。

Props 對(duì)渲染優(yōu)化的影響

默認(rèn)情況,只要組件重新渲染,React 會(huì)重新渲染所有被它嵌套的后代組件,即便組件的 props 沒(méi)有變更。如果試圖通過(guò) React.memo 和 React.PureComponent 優(yōu)化組件的渲染性能,那么要注意每個(gè) prop 的引用是否有變更。下面的示例試圖使用 React.memo 讓組件不重新渲染,但事與愿違,組件會(huì)重新渲染,代碼如下:

const MemoizedChildren = React.memo(Children)
function Parent() {
    const onClick = () => { /** todo*/}
    return <MemoizedChildren onClick={onClick}/>
}

上述代碼中,Parent 組件重新渲染會(huì)創(chuàng)建新的 onClick 函數(shù),所以對(duì) MemoizedChildren 而言,props.onClic k的引用有變化,最終被 React.memo 包裹的Children 會(huì)重新渲染,如果讓組件跳過(guò)重新渲染對(duì)你真的很重要,那么在上述代碼中將 React.memo 與 useCallback 配合使用才能達(dá)到目的。

總結(jié)

渲染與更新 DOM 是不同的事情,組件經(jīng)歷了渲染,DOM 不一定會(huì)更新,如果渲染組件返回的結(jié)果與上次的相同,那么它的 DOM 節(jié)點(diǎn)不需要有任何更新。與 React 渲染密切相關(guān)的還有另一個(gè)概念,即Immutability,在React 狀態(tài)的不變性一文已介紹過(guò)它。

到此這篇關(guān)于React重新渲染超詳細(xì)講解的文章就介紹到這了,更多相關(guān)React重新渲染內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React Native中Navigator的使用方法示例

    React Native中Navigator的使用方法示例

    導(dǎo)航組件Navigator可以讓我們客戶端在不同的頁(yè)面見進(jìn)行切換,下面這篇文章主要給大家介紹了關(guān)于React Native中Navigator的使用方法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • 淺談React雙向數(shù)據(jù)綁定原理

    淺談React雙向數(shù)據(jù)綁定原理

    在 React中是不存在雙向數(shù)據(jù)綁定的機(jī)制的,需要我們自己對(duì)其進(jìn)行實(shí)現(xiàn)。本文主要介紹一下React雙向數(shù)據(jù)綁定,感興趣的可以了解一下
    2021-11-11
  • react封裝全局彈框的方法

    react封裝全局彈框的方法

    這篇文章主要為大家詳細(xì)介紹了react封裝全局彈框的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • react-native 配置@符號(hào)絕對(duì)路徑配置和絕對(duì)路徑?jīng)]有提示的問(wèn)題

    react-native 配置@符號(hào)絕對(duì)路徑配置和絕對(duì)路徑?jīng)]有提示的問(wèn)題

    本文主要介紹了react-native 配置@符號(hào)絕對(duì)路徑配置和絕對(duì)路徑?jīng)]有提示的問(wèn)題,文中通過(guò)圖文示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • React樣式?jīng)_突解決問(wèn)題的方法

    React樣式?jīng)_突解決問(wèn)題的方法

    本文主要介紹了React樣式?jīng)_突解決問(wèn)題的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • React模擬實(shí)現(xiàn)Vue的keepAlive功能

    React模擬實(shí)現(xiàn)Vue的keepAlive功能

    Vue中,keep-alive組件可以緩存組件狀態(tài),在路由切換時(shí)重新掛載,實(shí)現(xiàn)這一功能在React中并不簡(jiǎn)單,但我們可以借助一個(gè)第三方庫(kù)——react-activation 來(lái)模擬Vue的keep-alive功能,需要的朋友可以參考下
    2024-10-10
  • 使用useImperativeHandle時(shí)父組件第一次沒(méi)拿到子組件的問(wèn)題

    使用useImperativeHandle時(shí)父組件第一次沒(méi)拿到子組件的問(wèn)題

    這篇文章主要介紹了使用useImperativeHandle時(shí)父組件第一次沒(méi)拿到子組件的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • React 路由react-router-dom示例詳解

    React 路由react-router-dom示例詳解

    一個(gè)路由就是一個(gè)映射關(guān)系(key:value),key為路徑, value可能是function或component,本文給大家介紹React 路由react-router-dom詳解,感興趣的朋友跟隨小編一起看看吧
    2024-01-01
  • 使用Ant Design Anchor組件的一個(gè)坑及解決

    使用Ant Design Anchor組件的一個(gè)坑及解決

    這篇文章主要介紹了使用Ant Design Anchor組件的一個(gè)坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 淺談react性能優(yōu)化的方法

    淺談react性能優(yōu)化的方法

    這篇文章主要介紹了淺談react性能優(yōu)化的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09

最新評(píng)論