前兩篇文章,javascript
深刻了Hook的源碼。本文將以useState
和useEffect
爲主,總結一下Hook的相關內容, 先貼出示例代碼:git
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對象的指針,會造成一個環形鏈表。github
對於state-hook
,其setState
函數經過閉包保存了對應的hook對象的引用。調用setState
對狀態值進行更新時,每調用一次setState
,都會修改hook
對象上的queue
屬性。queue
屬性保存着hook的更新信息。setState
執行完後,對應的hook對象上的memorized
值就是最新的了。數組
對於effect-hook
,每次組件渲染時,都會進入effect-hook
的邏輯:首先判斷deps
數組內的值較上一次有無變化。若是無變化,則會給該effect打上忽略的tag。若是跟上一次組件渲染時有變化,最終會先執行destory
函數(即useEffect
中return的函數),而後執行create
函數。閉包
對於反作用,react每次都會生成新的effect鏈,若是deps
數組內的值變化了,那麼新的effect對象還會賦值給effect-hook
的memorizedState
屬性。函數
本例中,假設咱們在title那裏,輸入了hello,組件更新完成後,Fiber節點上的hook信息以下:post
稍微總結一下,關於react hook,咱們須要知道如下幾點:ui
一、react hook大量採用了鏈表的結構。
二、代碼中hook的書寫順序,決定了最終hook在fiber上的存儲順序。
三、組件每次渲染的時候,hook的代碼都會執行一次,而且將上一次的hook對象都clone一遍,返回最新的hook的state以及對應的更新函數。在state的更新函數中,以閉包的形式保存了對應hook對象的引用。
至此,react hook源碼解析系列暫時告一段落了。儘管有許多地方沒有我還沒徹底理解,有的地方也沒有講述清楚,可是對react hook的總體實現方式已經有了進一步深刻的理解了。符合預期。最後,推薦一篇hook相關的文章: