DOM みたいに使いまわしてはいけないものって思ってました
あるコードをみたときに props として受け取るのがコンポーネントではなく Element
それを複数箇所で使ってました
例えば
const Component1 = () => {
return (
<Component2 elem={<Foo/>} />
)
}
const Component2 = ({ elem }) => {
return (
<div>
{elem}
<Component3 elem={elem} />
{elem}
</div>
)
}
みたいな感じのもの
他には
export default {
elem: <Bar />
}
みたいにモジュールが export する固定値が Element になっていて 全体で同じ Element が共有されるもの
正しく動かない気がしますが動くんでしょうか
こういうときってコンポーネントを渡して使う側で Element 化するか 関数で渡して使う側で呼び出して Element を受け取るとかしないといけないものだと思ってました
ただどう言う風に問題が出るのかまで把握できてなかったので色々試した……のですが 結局問題は起こせませんでした
state を使っても共有されたりしませんし 使用箇所全てで正常に動作しています
useMemo で Element をメモすることで重たい処理をスキップできていたので Element にいろいろな情報が残っていて共有すると問題が起きそうには思うのですけど
再レンダリングの有無を確認すると 前回のレンダリングのときとツリー構造の同じ場所で同じ Element が使われていればその Element は再レンダリングされてないようです
同じ場所で同じ Element でも一旦別の Element に切り替わると再レンダリングされてました
const elem1 = <Foo />
const elem2 = <Bar />
const Component = () => {
const [state, setState] = useState(false)
return (
<div onClick={() => setState(!state)}>
{state ? elem1 : elem2}
</div>
)
}
このコードで state による elem1 と elem2 の分岐をなくし 常に elem1 とすると state を切り替えても Foo 関数は実行されません
elem1 と elem2 で切り替えるようにすると 切り替えるごとに Foo または Bar 関数が実行されました
前回との比較で参照が同じ Element だとスキップみたいな扱いなのでしょうか
Element 自体がイミュータブルで中にレンダリングの情報を持たないなら共有しても影響なさそうです
Element である以上使うときに props は変更できませんし 再レンダリングはされなくても困らないはずです