react 16.8後的Hook API是如何運作的
在 2018 年底的 react16.8 推出之後,我們的function components
開始有 hook api 可用,就算是function components
也可以有狀態,但有想過為什麼可以這樣嗎?本篇文章是在消化過數個網路上解釋 hook 是如何實作的資源之後再加上我自己的一些想法而產生學習紀錄。
不然也先來想想為什麼 class component 為什麼可以有狀態好了
class component 時代時,我們的 component 是class
,它可以被 react 拿去 new,
這在react官方文件裡的其中一篇 - implementation-notes中有提到:
If App is a class, the reconciler will instantiate an App with new App(props),
call the componentWillMount() lifecycle method,
and then will call the render() method to get the rendered element.
每 new 一次就會有一個依照那個 class 而製造出來的實體(instance)產生(在那個 class 裡,某些狀況下,也就是黑魂梗!!那個 JS 裡的勸退哥this
啦*),
the template, if you are interested
在這個實體上自然就能夠綁上它的OO 概念裡有人講 property, 有人講 field, 有人講 member, 有人講attribute....。對應屬性
*,能夠用來表現它的狀態-state 跟 行為-method,比說一個 ListItem 各自有自己的`state`,有很多個 ListItem 時,各自能取到各自的 state,不會取錯。每一個實體能夠保有自己的狀態*,所以這在使用上沒有問題。
那換到 function component 的時候呢?
一樣以 ListItem 為例,假設今天寫了一個 function component 式的 ListItem component,一個列表裡會有很多個 ListItem,萬一今天每個 item 都必須要有自己的狀態,但是每一個 item 都是同一個 ListItem component 執行之後再經過某種轉換(光是這個轉換就可以寫一篇很大篇的文章,這裡就先不深入了)產生出來的,在 function 的情況下 每個item都必須要有自己的狀態
這件事是無法成立的。雖然 JS 裡的 function 也是 Object, 每個function也能夠有自己的nampspace
如:
function myFunc() {
// doSomething
}
myFunc.myState = 123 // 但我相信一般人也不會這樣寫,會很混亂...
myFunc.myState === 123 //true
這個myState
只會是一個記憶體上的位置,不會是呼叫同一個 function 好幾次並對它 update 後還能夠各自保持各次呼叫時的狀態那樣的狀況。
要做到 同一個 function,但是在不同次的呼叫的時候又能夠存取當下屬於那次呼叫的狀態
,也不是做不到,
因為,只要把那個狀態放在function外面
,然後在每次執行時知道現在是執行到第幾次
,要去那邊取第幾個
就行了。 是的,其實就是這麼簡單...。
這些狀態其實就是放在React
這個命名空間底下!!!
React 底下有一個array
專門存放每次用了 hook api <useState 的時候是 value,useEffect 時就是`function`(可以想成是在之後某個時間點要執行的 callback)之後傳進去的東西*,然後還會記住一個index
,當我們使用 useState
, useEffect
這些 API 的時候,這個 index 就會++
,所以不管是取值或是改變值,或是 做某些動作(執行傳進useEffect裡的function)
,都會從那個array
裡用那個index
取出來。因為造成`上一次執行這個function`時跟`這一次執行這個function`時取到的 index`不同`這也是 react 官方文件裡告訴我們 hook 不能夠在if...else跟loop裡使用的原因*,因為這可能會造成那個 index++錯誤,index 錯誤的話,在從 那個array
裡拿出東西時,就會拿錯
這裡附上一個為了讓code一看就懂,超級簡化版的實作:
或者來看看@swyx的完整版本 codesandbox link
reference
Getting Closure on React Hooks by Shawn Wang | JSConf.Asia 2019 @swyx 在2019/07在新加坡舉辦的JSConf asia 2019時的talk,本篇文章裡大多數內容是從這個talk裡得到啟發
- Rodrigo Pombo - Build your own React
@pomber的一篇講解react實作的互動式教學,其中也有說到關於Hook api是如何實作的部份 - Rudi Yardley - React hooks: not magic, just arrays
一篇可以讓人了解hook所儲存的資料是在component外部的一個array裡的直接了當的文章。