跟着官方文檔能學懂Hooks就怪了

回想下你入門Hooks的過程,是否是經歷過:html

  1. 類比ClassComponent的生命週期,學習Hooks的執行時機前端

  2. 慢慢熟練之後,發現Hooks的執行時機和生命週期又有些不一樣。好比componentWillReceiveProps對應哪一個Hooksreact

  3. 感到困惑,去搜一些Hooks原理層面的文章閱讀數組

做爲一個API,不應簡簡單單、可可愛愛的照着文檔調用就行麼,Hooks爲何這麼難?markdown

React官方也發現了這個問題,在React要重寫文檔了講到,React要基於Hooks重寫文檔。架構

本文主要包括2方面內容:app

  1. 解釋Hooks難學的緣由異步

  2. 給出學習Hooks的建議ide

React的底層架構

能夠用一個公式歸納React函數

const UI = fn(state);
複製代碼

視圖能夠看做狀態通過函數的映射。

用戶與界面的交互,能夠看做這個公式的不斷執行。

這個公式太精簡了,沒有解釋state(狀態)從哪兒來,咱們擴展下:

const state = reconcile(update);
const UI = fn(state);
複製代碼
  1. 用戶交互產生update(更新)

  2. update通過reconcile步驟計算出當前應用的state

  3. fnstate映射爲視圖變化(UI)

咱們給fn起個名字:commit

const state = reconcile(update);
const UI = commit(state);
複製代碼

那麼update在哪裏產生呢?固然來自於用戶交互,好比:點擊事件。

因此React的底層架構能夠簡化爲三步:

  • 用戶交互產生update

  • state = reconcile(update);

  • UI = commit(state);

瞭解了底層架構,咱們再來看經過類比ClassComponent學習Hooks會帶來的問題。

生命週期函數的抽象層級

咱們已經有了完整的驅動視圖更新的底層架構,開發者該怎麼操做這套架構呢?

能夠用計算機的抽象層級來類比:

高層:應用程序
中層:操做系統
底層:計算機組成架構
複製代碼

對應React

高層:應用程序       ClassComponent生命週期
中層:操做系統       介入架構的API
底層:計算機組成架構  React底層架構
複製代碼

能夠看到,生命週期函數屬於抽象程度比較高的層次。這麼設計也是爲了讓開發者更容易上手React

設想一個Vue2開發者要轉React技術棧,只須要類比Vue的生命週期來學習React的生命週期就好了。

這一切在Hooks到來前都沒問題,然而......

Hooks的抽象層級

Hooks屬於中等抽象層級。也就是說,Hooks直接介入底層架構的運行流程。

高層:應用程序       
中層:操做系統       Hooks
底層:計算機組成架構  React底層架構      
複製代碼

當咱們用生命週期函數來類比Hooks時,實際上是用高抽象層級的事物來描述低抽象層級的事物。

動物 --> 哺乳動物 --> 牛 --> 奶牛

對於一個只見過奶牛,再沒見過其餘動物的人,你怎麼向他解釋哺乳動物是啥?

正是因爲抽象層級的不對稱,形成經過生命週期函數類比學習Hooks會遇到問題。

該怎麼學Hooks

既然Hooks屬於中等抽象層,離底層很近,那麼更好的學習方式是經過底層向上學習。

祭出咱們的三步公式:

  • 用戶交互產生update

  • state = reconcile(update);

  • UI = commit(state);

對照公式,咱們來說解幾個常見hook的工做流程:

useState

舉個例子:

function App() {
  const [state, updateState] = useState(0);
  return <div onClick={() => updateState(state + 1)}></div>;
}
複製代碼

useState返回值數組包含:

  1. 保存的state

  2. 改變state的方法updateState

對照公式,state屬於公式步驟2計算得出的:

  • state = reconcile(update);

此時視圖尚未更新。

用戶點擊div觸發updateState,對應公式步驟1:

  • 用戶交互產生update

因此調用updateState能開啓底層架構的三步運行流程。

reconcile計算出state後就會進入第三步:

  • UI = commit(state);

最終渲染視圖。

useEffect

舉個例子:

useEffect(doSomething, [xx, yy])
複製代碼

useEffect的回調函數doSomething在第三步執行完成後異步調用:

  • UI = commit(state);

因此在doSomething函數內部能獲取到完成更新的視圖。

第二個參數[xx, yy]做爲依賴項,決定了doSomething是否會被調用。

useLayoutEffect

不一樣於useEffect在第三步執行完成後異步調用,useLayoutEffect會在第三步執行完UI操做後同步執行。

useRef

以上例子能夠看到,useStateuseEffect分別在三步流程的不一樣步驟被觸發,他們的觸發時機是肯定的。

那麼這三個步驟如何交流呢?經過useRef

useState做用於第1、二步,useLayoutEffect做用於第三步,useEffect做用於第三步完成後。

使用useRef,就能達到在不一樣步驟間共享引用類型數據的目的。

能夠看到,React爲底層架構三步工做流程的每一步提供了對應的hook,同時提供了串聯這三步工做流程的hook

開發者只須要根據業務須要,經過基礎Hooks組裝出自定義hook,就能在底層架構運行流程的各個時期運行邏輯。

自底向上學習是本末倒置麼?

有同窗會反駁:以前學React得學生命週期函數的執行時機,如今學Hooks得學底層架構運行流程。難道不是本末倒置,更復雜了麼?

其實否則。我問你幾個問題:

  1. componentWillReceiveProps爲何被標記爲unsafe

  2. getDerivedStateFromProps用過麼?

  3. this.setState是同步仍是異步的?

這些和生命週期函數相關的問題一點都不簡單!不少用了幾年React的前端不必定回答的上。

做爲高層次抽象,生命週期函數隱藏了太多實現細節。同時React又太靈活,不像Vue經過模版語言限制了開發者的操做。

結果就是:不一樣React開發者寫出各類奇奇怪怪的ClassComponent

反觀經過底層架構運行流程學習Hooks

  • 底層架構運行流程就是React的絕對真理,不會隱藏更多抽象

  • Hooks的寫法規範限制了開發者的奇葩操做

這裏的惟一問題,就是缺乏一份從底層出發的文檔。這也是React要重寫文檔的初衷。

對於熟練使用React的開發者,在官方新文檔出來前,能夠參考React技術揭祕學習。

這裏再提供些其餘視角聊Hooks的文章:

相關文章
相關標籤/搜索