本文首發於公衆號:符合預期的CoyPan
前兩篇文章,深刻了Hook的源碼。本文將以useState
和useEffect
爲主,總結一下Hook的相關內容,javascript
先貼出示例代碼:java
const App = () => { const [title, setTitle] = useState(''); const [fontSize, setFontSize] = useState('13'); useEffect(() => { document.title = title; },[title]); useEffect(() => { document.body.style.fontSize = `${fontSize}px`; }, [fontSize]); return <React.Fragment> <input value={title} onChange={e => setTitle(e.target.value)} /> <input value={fontSize} onChange={e => setFontSize(e.target.value)} /> <p>Hello World</p> </React.Fragment> };
組件首次掛載的時候,依次執行四行useXXX
的代碼,生成4個hook對象,按照順序造成完整的hook鏈,掛載在Fiber對象的memorizedState
屬性上。hook對象上的memorizedState
屬性表示當前hook對象的值。對於effect-hook
,其memorizedState
屬性的值爲一個對象(effect對象),包含了一個指向下一下effect-hook
的effect對象的指針,會造成一個環形鏈表。react
對於state-hook
,其setState
函數經過閉包保存了對應的hook對象的引用。調用setState
對狀態值進行更新時,每調用一次setState
,都會修改hook
對象上的queue
屬性。queue
屬性保存着hook的更新信息。setState
執行完後,對應的hook對象上的memorized
值就是最新的了。git
對於effect-hook
,每次組件渲染時,都會進入effect-hook
的邏輯:首先判斷deps
數組內的值較上一次有無變化。若是無變化,則會給該effect打上忽略的tag。若是跟上一次組件渲染時有變化,最終會先執行destory
函數(即useEffect
中return的函數),而後執行create
函數。github
對於反作用,react每次都會生成新的effect鏈,若是deps
數組內的值變化了,那麼新的effect對象還會賦值給effect-hook
的memorizedState
屬性。數組
本例中,假設咱們在title那裏,輸入了hello,組件更新完成後,Fiber節點上的hook信息以下:閉包
稍微總結一下,關於react hook,咱們須要知道如下幾點:函數
一、react hook大量採用了鏈表的結構。spa
二、代碼中hook的書寫順序,決定了最終hook在fiber上的存儲順序。指針
三、組件每次渲染的時候,hook的代碼都會執行一次,而且將上一次的hook對象都clone一遍,返回最新的hook的state以及對應的更新函數。在state的更新函數中,以閉包的形式保存了對應hook對象的引用。
至此,react hook源碼解析系列暫時告一段落了。儘管有許多地方沒有我還沒徹底理解,有的地方也沒有講述清楚,可是對react hook的總體實現方式已經有了進一步深刻的理解了。符合預期。最後,推薦一篇hook相關的文章:
https://github.com/shanggqm/b...