你應該理解的react知識點

前言

最近在準備面試。複習了一些react的知識點,特此總結。react

開始

React 生命週期

react 16之前的生命週期是這樣的面試

組件在首次渲染時會被實例化,而後調用實例上面的componentWillMount,render和componentDidMount函數。組件在更新渲染時能夠調用componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render和componentDidUpdate函數。組件在卸載時能夠調用componentWillUnmount函數。算法

借圖:瀏覽器

image.png

從 React v16.3 開始,React 建議使用getDerivedStateFromPropsgetSnapshotBeforeUpdate兩個生命週期函數替代 componentWillMountcomponentWillReceivePropscomponentWillUpdate三個生命週期函數。這裏須要注意的是 新增的兩個生命週期 函數和原有的三個生命週期函數必須分開使用,不能混合使用併發

目前的生命週期(借圖):dom

image.png

componentWillMount存在的問題異步

有人認爲在componentWillMount中能夠提早進行異步請求,避免白屏。可是react在調用render渲染頁面的時候,render並不會等待異步請求結束,再獲取數據渲染。這麼寫是有潛在隱患的。函數

而在react fiber以後 可能在一次渲染中屢次調用。緣由是:react fiber技術使用增量渲染來解決掉幀的問題,經過requestIdleCallback調度執行每一個任務單元,能夠中斷和恢復,生命週期一旦中斷,恢復以後會從新跑一次以前的生命週期佈局

新的生命週期動畫

static getDerivedStateFromProps

  • 觸發時間(v16.4修正):組件每次被rerender的時候,包括在組件構建以後(render以前最後執行),每次獲取新的props或state以後。在v16.3版本時,組件state的更新不會觸發該生命週期
  • 每次接收新的props以後都會返回一個對象做爲新的state,返回null則說明不須要更新state
  • 配合componentDidUpdate,能夠覆蓋componentWillReceiveProps的全部用法

getSnapshotBeforeUpdate

  • 觸發時間: update發生的時候,在render以後,在組件dom渲染以前。
  • 返回一個值,做爲componentDidUpdate的第三個參數。
  • 配合componentDidUpdate, 能夠覆蓋componentWillUpdate的全部用法。

React Fiber

因爲React渲染/更新過程一旦開始沒法中斷,持續佔用主線程,主線程忙於執行JS,無暇他顧(佈局、動畫),形成掉幀、延遲響應(甚至無響應)等不佳體驗。fiber應運而生。

Fiber 是對react reconciler(調和) 核心算法的重構。關鍵特性以下:

  • 增量渲染(把渲染任務拆分紅塊,勻到多幀)
  • 更新時可以暫停,終止,複用渲染任務
  • 給不一樣類型的更新賦予優先級
  • 併發方面新的基礎能力

增量渲染用來解決掉幀的問題,渲染任務拆分以後,每次只作一小段,作完一段就把時間控制權交還給主線程,而不像以前長時間佔用。

Fiber tree

  • Fiber以前的reconciler(被稱爲Stack reconciler)自頂向下的遞歸mount/update,沒法中斷(持續佔用主線程),這樣主線程上的佈局、動畫等週期性任務以及交互響應就沒法當即獲得處理,影響體驗。
  • Fiber解決這個問題的思路是把渲染/更新過程(遞歸diff)拆分紅一系列小任務,每次檢查樹上的一小部分,作完看是否還有時間繼續下一個任務,有的話繼續,沒有的話把本身掛起,主線程不忙的時候再繼續。

fiber樹實際上是一個單鏈表結構,child指向第一個子節點,return指向父節點,sibling指向下個兄弟節點。結構以下:

// fiber tree節點結構
{
    stateNode,
    child,
    return,
    sibling,
    ...
}

Fiber reconciler

reconcile過程分爲2個階段:

1.(可中斷)render/reconciliation 經過構造workInProgress tree得出change

2.(不可中斷)commit 應用這些DOM change(更新DOM樹、調用組件生命週期函數以及更新ref等內部狀態)

構建workInProgress tree的過程就是diff的過程,經過requestIdleCallback來調度執行一組任務,每完成一個任務後回來看看有沒有插隊的(更緊急的),每完成一組任務,把時間控制權交還給主線程,直到下一次requestIdleCallback回調再繼續構建workInProgress tree

生命週期也被分紅了兩個階段:

// 第1階段 render/reconciliation
componentWillMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate

// 第2階段 commit
componentDidMount
componentDidUpdate
componentWillUnmount

第1階段的生命週期函數可能會被屢次調用,默認以low優先級執行,被高優先級任務打斷的話,稍後從新執行。

fiber tree與workInProgress tree

雙緩衝技術:指的是workInProgress tree構造完畢,獲得的就是新的fiber tree,而後把current指針指向workInProgress tree,因爲fiber與workInProgress互相持有引用,舊fiber就做爲新fiber更新的預留空間,達到複用fiber實例的目的。

每一個fiber上都有個alternate屬性,也指向一個fiber,建立workInProgress節點時優先取alternate,沒有的話就建立一個

let workInProgress = current.alternate;
if (workInProgress === null) {
  //...
  workInProgress.alternate = current;
  current.alternate = workInProgress;
} else {
  // We already have an alternate.
  // Reset the effect tag.
  workInProgress.effectTag = NoEffect;

  // The effect list is no longer valid.
  workInProgress.nextEffect = null;
  workInProgress.firstEffect = null;
  workInProgress.lastEffect = null;
}

這麼作的好處:

  • 可以複用內部對象(fiber)
  • 節省內存分配、GC的時間開銷

fiber 中斷 恢復

中斷:檢查當前正在處理的工做單元,保存當前成果(firstEffect, lastEffect),修改tag標記一下,迅速收尾並再開一個requestIdleCallback,下次有機會再作

斷點恢復:下次再處理到該工做單元時,看tag是被打斷的任務,接着作未完成的部分或者重作

P.S.不管是時間用盡「天然」中斷,仍是被高優任務粗暴打斷,對中斷機制來講都同樣。

React setState

在代碼中調用setState函數以後,React 會將傳入的參數對象與組件當前的狀態合併,而後觸發所謂的調和過程(Reconciliation)。通過調和過程,React 會以相對高效的方式根據新的狀態構建 React 元素樹而且着手從新渲染整個UI界面。在 React 獲得元素樹以後,React 會自動計算出新的樹與老樹的節點差別,而後根據差別對界面進行最小化重渲染。在差別計算算法中,React 可以相對精確地知道哪些位置發生了改變以及應該如何改變,這就保證了按需更新,而不是所有從新渲染。

setState調用時有時是同步的(settimeout,自定義dom事件),有時是異步的(普通調用)

React 事件機制

React事件是經過事件代理,在最外層的 document上對事件進行統一分發,並無綁定在真實的 Dom節點上。
並且react內部對原生的Event對象進行了包裹處理。具備與瀏覽器原生事件相同的接口,包括 stopPropagation()preventDefault()

image.png

相關文章
相關標籤/搜索