前言
最近做了不少面試
經過各種自信心的打擊之後
發現自己對 react 其實沒有想像中那麼了解
明明每天跟他朝夕相處,以為很懂他
記錄一下其中一個被問卻觀念錯誤的問題
Render and Commit
不是什麼複雜的概念
就只是考 react 一個蠻基本的概念
在 react docs 就有的 Render phase 和 Commit phase
import {useEffect} from "react"
export default function Parent() {
console.log('I am parent component')
useEffect(() => {
console.log('I am parent useEffect')
}, [])
return <div>I am parent
<Child />
</div>
}
function Child() {
console.log('I am child component')
useEffect(() => {
console.log('I am child useEffect')
}, [])
return <>I am child</>
}
以上方程式碼作為範例
Render Phase
先說明一下名詞
這裡的 render 和一般我們熟知的 react 渲染其實不是一個意思
render phase 就是 react 在計算的一個過程
利用遞迴最終產生一個 React Element 樹狀結構結果
如果是 rerender ,一樣會產生一個 React element
差異就是會用當前 Fiber tree 做比對,來確認需要更新的 dom
diffing 就是在這裡完成的
在這個 phase 中,就會由上到下執行所有的 component
因此回到上面範例就可以知道
最先 console 出來的兩個順序就是
// I am parent component
// I am child component
Commit Phase
根據所獲得的 React element tree 做 Dom 節點的創建
如果是 rerender 的 commit phase,就是會「更新」Dom 節點
那當然也是透過 react 計算出最少操作需要的節點
而 commit phase 是遵循「深度優先」原則
所以結果想當然會是
// I am child useEffect
// I am parent useEffect
useLayoutEffect & useEffect
由 commit phase 也可以理解到這兩者的差異
useLayoutEffect 是在 commit phase 同步執行的,也就是在 DOM 更新後,但在瀏覽器繪製前
useEffect 則是在 commit phase 後執行
useLayoutEffect 多用來針對 dom 的測量或更新用的