參考資料:
深入React的生命週期(上):出生階段(Mount)
深入React的生命週期(下):更新(Update)
精讀《useEffect 完全指南》
React元件重新渲染理解 & 優化大全
React渲染順序及useEffect執行順序探究(含並行模式)
同樣還是可以把元件的狀態分為mount、update和unmount。
即使用ReactDOM.createRoot(DOM).render(<App />)
渲染元件時。
在元件的不同階段,呼叫順序如下
useState
等hooks取初始值,如果用callback初始化,則會呼叫初始化函數useEffect
註冊的函數,呼叫順序就是useEffect
在函數體裡出現的順序函數體:正常呼叫,取最新state和ref的值
clean函數:如果依賴項A=[…]
發生改變,則會呼叫,但若有其它依賴項B
也變了,卻沒列進依賴項裡,這些未註冊依賴項會使用最後一次A=[…]
發生改變時的B的值。因為這是clean函數最新的定義。
樣例可見React函數式元件渲染順序探究(Demo),元件依賴了name和state,但只註冊了state這一個依賴項。
effect函數:如果依賴項A=[…]
發生改變,則會呼叫,但若有其它依賴項B
也變了,卻沒列進依賴項裡,這些未註冊依賴項會使用最後一次A=[…]
發生改變時的B的值。因為這是effect函數最新的定義。
clean函數:會呼叫一遍所有useEffect
返回的clean函數,呼叫順序也是註冊順序。同樣,也取的是它最新的定義。
假設有兩個effect,都有未註冊依賴項B
。但它們一個依賴項為A=[…]
,另一個為[]
。
如果最開始B=1
,而A
變的時候B=2
,最後unmount的時候,前者的B=2
,後者的B=1
,因為後者的clean函數並未更新。
如果有一個這樣的component:
<A>
<A1>
<A1_1/>
<A1_2/>
</A1>
<A2>
<A2_1/>
<A2_2/>
</A2>
</A>
[A, A1, A1_1, A1_2, A2, A2_1, A2_2]
[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
。如果上述的component變成了如下,A重新渲染。
<A>
<A2>
<A2_1/>
<A2_2/>
</A2>
<A1>
<A1_1/>
<A1_2/>
</A1>
</A>
假設這裡A1設定了key,而A2沒有:
[A1, A1_1, A1_2, A2, A2_1, A2_2]
。[A2, A2_1, A2_2]
[A1_1, A1_2, A1]
[A2_1, A2_2, A2, A1_1, A1_2, A1]
。即使用StrictMode
渲染元件時。
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
與16最大的區別是:
(1)函數體都會被呼叫2遍
(2)新mount的元件都會再次呼叫一遍clean和effect
有點類似於, mount (React 18)
約等於mount(React 16) + update(React 16)
所以:
第一次body即mount的body,第二次body是update的body
但也不完全相同,比如,如果使用callback來初始化state的值時,mount的時候呼叫的兩遍函數體,都是會呼叫這個callback的,而不是一次呼叫一次不呼叫。
第一次effect是mount的effect
接下來的clean和effect是update時的clean+effect
如果有一個這樣的component:
<A>
<A1>
<A1_1/>
<A1_2/>
</A1>
<A2>
<A2_1/>
<A2_2/>
</A2>
</A>
[A, A1, A1_1, A1_2, A2, A2_1, A2_2]
。由於會叫兩遍,實際上是[A, A, A1, A1, A1_1, A1_1, A1_2, A1_2, A2, A2, A2_1, A2_1, A2_2, A2_2]
[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
。[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
。[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
。如果上述的component變成了如下,A重新渲染。
<A>
<A2>
<A2_1/>
<A2_2/>
</A2>
<A1>
<A1_1/>
<A1_2/>
</A1>
</A>
假設這裡A1設定了key,而A2沒有:
[A1, A1_1, A1_2, A2, A2_1, A2_2]
。同樣會呼叫2次。[A2, A2_1, A2_2]
[A1_1, A1_2, A1]
[A2_1, A2_2, A2, A1_1, A1_2, A1]
。[A2_1, A2_2, A2]
[A2_1, A2_2, A2]