回想下你入門Hooks
的過程,是否是經歷過:html
類比ClassComponent
的生命週期,學習Hooks
的執行時機前端
慢慢熟練之後,發現Hooks
的執行時機和生命週期
又有些不一樣。好比componentWillReceiveProps
對應哪一個Hooks
?react
感到困惑,去搜一些Hooks
原理層面的文章閱讀數組
做爲一個API
,不應簡簡單單、可可愛愛的照着文檔調用就行麼,Hooks
爲何這麼難?markdown
React
官方也發現了這個問題,在React要重寫文檔了講到,React
要基於Hooks
重寫文檔。架構
本文主要包括2方面內容:app
解釋Hooks
難學的緣由異步
給出學習Hooks
的建議ide
能夠用一個公式歸納React
:函數
const UI = fn(state);
複製代碼
視圖
能夠看做狀態
通過函數
的映射。
用戶與界面的交互,能夠看做這個公式的不斷執行。
這個公式太精簡了,沒有解釋state
(狀態)從哪兒來,咱們擴展下:
const state = reconcile(update);
const UI = fn(state);
複製代碼
用戶交互產生update
(更新)
update
通過reconcile
步驟計算出當前應用的state
fn
將state
映射爲視圖變化(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
底層:計算機組成架構 React底層架構
複製代碼
當咱們用生命週期函數
來類比Hooks
時,實際上是用高抽象層級
的事物來描述低抽象層級
的事物。
動物 --> 哺乳動物 --> 牛 --> 奶牛
對於一個只見過奶牛,再沒見過其餘動物的人,你怎麼向他解釋哺乳動物
是啥?
正是因爲抽象層級的不對稱,形成經過生命週期函數
類比學習Hooks
會遇到問題。
既然Hooks
屬於中等抽象層,離底層很近,那麼更好的學習方式是經過底層向上學習。
祭出咱們的三步公式:
用戶交互產生update
state
= reconcile(update
);
UI
= commit(state
);
對照公式,咱們來說解幾個常見hook
的工做流程:
舉個例子:
function App() {
const [state, updateState] = useState(0);
return <div onClick={() => updateState(state + 1)}></div>;
}
複製代碼
useState
返回值數組包含:
保存的state
改變state
的方法updateState
對照公式,state
屬於公式步驟2計算得出的:
此時視圖尚未更新。
用戶點擊div
觸發updateState
,對應公式步驟1:
update
因此調用updateState
能開啓底層架構的三步運行流程。
當reconcile
計算出state
後就會進入第三步:
UI
= commit(state
);最終渲染視圖。
舉個例子:
useEffect(doSomething, [xx, yy])
複製代碼
useEffect
的回調函數doSomething
在第三步執行完成後異步調用:
UI
= commit(state
);因此在doSomething
函數內部能獲取到完成更新的視圖。
第二個參數[xx, yy]
做爲依賴項,決定了doSomething
是否會被調用。
不一樣於useEffect
在第三步執行完成後異步調用,useLayoutEffect
會在第三步執行完UI
操做後同步執行。
以上例子能夠看到,useState
與useEffect
分別在三步流程的不一樣步驟被觸發,他們的觸發時機是肯定的。
那麼這三個步驟如何交流呢?經過useRef
。
useState
做用於第1、二步,useLayoutEffect
做用於第三步,useEffect
做用於第三步完成後。
使用useRef
,就能達到在不一樣步驟間共享引用類型數據的目的。
能夠看到,React
爲底層架構三步工做流程的每一步提供了對應的hook
,同時提供了串聯這三步工做流程的hook
。
開發者只須要根據業務須要,經過基礎Hooks
組裝出自定義hook
,就能在底層架構運行流程的各個時期運行邏輯。
有同窗會反駁:以前學React
得學生命週期函數
的執行時機,如今學Hooks
得學底層架構運行流程
。難道不是本末倒置,更復雜了麼?
其實否則。我問你幾個問題:
componentWillReceiveProps
爲何被標記爲unsafe
?
getDerivedStateFromProps
用過麼?
this.setState
是同步仍是異步的?
這些和生命週期函數
相關的問題一點都不簡單!不少用了幾年React
的前端不必定回答的上。
做爲高層次抽象,生命週期函數
隱藏了太多實現細節。同時React
又太靈活,不像Vue
經過模版語言
限制了開發者的操做。
結果就是:不一樣React
開發者寫出各類奇奇怪怪的ClassComponent
。
反觀經過底層架構運行流程
學習Hooks
:
底層架構運行流程
就是React
的絕對真理,不會隱藏更多抽象
Hooks
的寫法規範限制了開發者的奇葩操做
這裏的惟一問題,就是缺乏一份從底層
出發的文檔。這也是React
要重寫文檔的初衷。
對於熟練使用React
的開發者,在官方新文檔出來前,能夠參考React技術揭祕學習。
這裏再提供些其餘視角聊Hooks
的文章:
從理念
層面:代數效應與Hooks
從微觀
(代碼)層面:全部常見Hooks的源碼實現