重點: 1.二者函數簽名相同,調用方式是一致的
2. 怎么簡單進行選擇: 無腦選擇useEffect,除非運行效果和你預期的不一致再試試useLayoutEffect
區別詳解:
useEffect是異步執行,而且是在渲染被繪制到屏幕之后執行。
流程如下:
你以某種方式觸發了rerender(改變state,或者父組件發生rerender)
React渲染你的組件(調用組件函數)
屏幕在視覺上更新(真實dom操作)
然后useEffect運行
useLayoutEffect是同步執行,時機在渲染之后但在屏幕更新之前。
流程如下:
你以某種方式觸發了rerender(改變state,或者父組件發生rerender)
React渲染你的組件(調用組件函數)
useLayoutEffect運行,React等待它完成
屏幕在視覺上更新(真實dom操作)
代碼實戰:
const BlinkyRender = () => { const [value, setValue] = useState(0); useLayoutEffect(() => { if (value === 0) { setValue(10 + Math.random() * 200); } }, [value]); console.log('render', value); return ( <div onClick={() => setValue(0)}> value: {value} </div> ); };
當點擊div時,狀態立即改變(value重置為0),這將重新Render組件,然后運行Effect——將值設置為某個隨機數,並再次重新Render。
也就是是兩次Rerender會快速連續發生。分別換用useLayoutEffect和useEffect觀察有什么不同。
你會發現useLayoutEffect的版本會在組件render兩次的情況下僅在視覺上更新一次。而useEffect版本在視覺上也會呈現兩次,所以會看到閃爍,從0閃爍變成對應的隨機數。
所以到底什么時候使用useLayoutEffect呢?
如果你的組件在狀態更新時閃爍,比如它首先以部分就緒狀態呈現,然后立即以最終狀態重新呈現——這是一個很好的線索,是時候換useLayoutEffect了。
當您的更新是兩步(或多步)過程時,就會出現這種情況。你想在重新繪制屏幕之前一起批處理多個更新嗎,試試useLayoutEffect。
在大多數情況下,你的effect函數會在對應的依賴項如state或props改變時執行,而對應的回調邏輯往往不會立即影響或根本不影響頁面視覺。
比如發一個ajax請求
或者你設置一個了事件處理器
大多數時候,使用useEffect是正確的。如果您的代碼導致閃爍,切換到useLayoutEffect,看看是否有幫助。
因為useLayoutEffect是同步的,也就是阻塞的,在你的effect運行完之前,視覺不會更新。如果你的effect中有計算密集型代碼,它可能會導致性能體驗問題,比如卡頓。大多數effect在運行時並不需要"stop the world",普通的 useEffect幾乎可以滿足我們所有的需求。