React Hook源碼解析(三)

本文首發於公衆號:符合預期的CoyPan

寫在前面

前兩篇文章,深刻了Hook的源碼。本文將以useStateuseEffect爲主,總結一下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>
};

組件初次掛載

1.png

組件首次掛載的時候,依次執行四行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-hookmemorizedState屬性。數組

本例中,假設咱們在title那裏,輸入了hello,組件更新完成後,Fiber節點上的hook信息以下:閉包

2.png

總結

稍微總結一下,關於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...

最新的.png

相關文章
相關標籤/搜索