ソースコードからReact Componentがレンダリングされる条件をなんとなく理解しています
前提知識
-
なにかstateが変わるときには、schedulerというパッケージの経由うでFiberツリー全探索を促しています。そして、各ComponentのFiberに辿り着いたときに、Componentを実行するかどうかが条件あり。
-
ComponentがレンダリングさることはComponent関数が実行されることです。
ソースコードからの解析
実行するかどうかは上記なところから判断行われています。
つまり、実行しないなら、attemptEarlyBailoutIfNoScheduledUpdateになります。
それ以外な場合は、下のswitch文にはいって、Componentの種類によって、それぞれの分岐を実行します。
attemptEarlyBailoutIfNoScheduledUpdateにに入るためには以下の3つのところの条件を満たす必要があります。
レンダリングしない条件1
現在のpropsと前のpropsは同じメモリアドレスする必要があります。
データ構造はこのようになっています
{
type: 'div',
props: {
count: 0,
children: {
....
}
}
}
レンダリングしない条件2
LegacyContextの変化がないこと(LegacyContextよくわからない)
レンダリングしない条件3
updateとcontextの変化がないこと
checkScheduledUpdateOrContextの結果を見ています。checkScheduledUpdateOrContextの中身をみてみると以下の処理がされてます。
主に二箇所をみています。
Componentのlaneが変化があるかどうか。コメントのようにcomponentのstateの変化もしくはcontextの変化がるかどうかを検知
contextの変化があるかどうか。ここはよくわかりません。コメントのように、contextの変化が遅くなる場合も検知されられます。
例から説明
例1
import React, { useState } from 'react';
const A = () => {
console.log("A")
return (<div>
<div>A</div>
<B/>
</div>)
};
const B = (props) => {
console.log("B")
return (<C/>)
}
const C = (props) => {
console.log("C")
const [count, setCount] = useState(0);
return <div>
<button onClick={_=> setCount(f=>f + 1)}>click</button>
</div>
}
export default A
ボタンをクリックしたら、Cしか実行されてません。
流れは以下です
- ボタンクリックしたら、Fiberツリー全探索開始
- Aにたどりつけ、propsが変わってない、内部にstateとcontext変化なし、実行しません。
- Bにたどり着け、propsが変わってない、内部にstateとcontext変化なし、実行しません。
- Cにたどりつけ、propsが変わってないですが、内部にstate変化があり、実行します。
例2
import React, { useState } from 'react';
const A = () => {
console.log("A")
const [count, setCount] = useState(0);
return (
<div>
<button onClick={_=> setCount(f=>f + 1)}>click</button>
<div>A</div>
<B/>
<C/>
</div>
)
};
const B = (props) => {
console.log("B")
return (<div>B</div>)
}
const C = (props) => {
console.log("C")
return <div>
C
</div>
}
export default A
ボタンをクリックしたら、A,B,C全部実行されます。
流れは以下です。
- ボタンクリックしたら、Fiberツリー全探索開始
- Aにたどりつけ、propsが変わってないですが、内部にstate変化なし、実行します。そして、BとCのpropsを再作成します。
- Bにたどりつけます、step2により、propsが変わりましたので、実行します。
- Cにたどりつけます、step2により、propsが変わりましたので、実行します。
例3
import React, { useState } from 'react';
const A = () => {
console.log("A")
return (<div>
<div>A</div>
<B/>
<C/>
</div>)
};
const B = (props) => {
console.log("B")
return (<div>B</div>)
}
const C = (props) => {
console.log("C")
const [count, setCount] = useState(0);
return <div>
<button onClick={_=> setCount(f=>f + 1)}>click</button>
</div>
}
export default A
ボタンをクリックしたら、Cしか実行されてません。
流れは以下です
- ボタンクリックしたら、Fiberツリー全探索開始
- Aにたどりつけ、propsが変わってない、内部にstateとcontext変化なし、実行しません。
- Bにたどり着け、propsが変わってない、内部にstateとcontext変化なし、実行しません。
- Cにたどりつけ、propsが変わってないですが、内部にstate変化があり、実行します。
参考リンク
Discussion