生命週期的味道。
簡述
React render 完,瀏覽器 paint 之前,你想做什麼?
一樣是 todo list 的範例,假設我在讀 loaclStorage
資料的時候是這樣寫的:
1 | function App() { |
這時候就會出現「閃一下」的問題,像這樣:
(我電腦寫不出這種效果,可能是閃太快的關係吧,所以改貼 Lidemy 的影片內容)
這是因為執行順序是這樣:
- 第一次 render,瀏覽器 paint 初始值的
todos
- 執行
useEffect
,讀取loaclStorage
,更新todos
的 state - state 變了所以再 render 一次,瀏覽器再 paint 成新的
todos
這就是為什麼會「閃一下」,因為 useEffect
是在瀏覽器 paint 完以後才會被執行的 hook,所以一開始會先顯示預設的 todos
,接著執行 useEffect
時改了 state,而 state 改變後又重新 render 了一次畫面,最後顯示新的 todos
。
可以參考這張圖,大概理解一下 hook 的生命週期
總之一定要知道 useEffect
是讚 paint 完以後才會被執行就對了。
回到一開始的問題,那要怎麼解決才好?
從上面的圖你應該能注意到一個東西是「Run LayoutEffects」,看起來就是在說它是跑在「Browser paints screen」以前的 hook,那麼是不是用這個就可以解決了?
沒錯,正是如此哦!
1 | useLayoutEffect(() => { |
改成這樣以後的執行順序就會變成:
- 第一次 render,進入瀏覽器 paint 以前的 hook
- 執行
useLayoutEffect
,讀取localStorage
,更新todos
的 state - state 變了所以再 render 一次,瀏覽器再把
todos
給 paint 出來
因為是在瀏覽器把畫面 paint 出來以前就先更新了 state,所以原本的 state 在被 render 出來之前就被覆寫掉了,因此最後 paint 時才會是新的 state。(不懂的話就看著圖,想想看每一步的流程應該就會懂了)