Parent コンポーネントの内側に Child コンポーネントを配置するとき Parent コンポーネントの中で Child を作るんじゃなくて Parent を作る側で Child も作って Parent に渡すのが良いとか
コードにするとこういうのです
const App = () => {
return (
<Parent />
)
}
const Parent = () => {
console.log("Parent")
const [state, setState] = useState(0)
return (
<div>
<button onClick={() => setState(state + 1)}>{state}</button>
<div><Child /></div>
</div>
)
}
const Child = () => {
console.log("Child")
return (
<div>child</div>
)
}
これの代わりに
const App = () => {
return (
<Parent>
<Child />
</Parent>
)
}
const Parent = ({ children }) => {
console.log("Parent")
const [state, setState] = useState(0)
return (
<div>
<button onClick={() => setState(state + 1)}>{state}</button>
<div>{children}</div>
</div>
)
}
const Child = () => {
console.log("Child")
return (
<div>child</div>
)
}
にします
App コンポーネントで Child をつくって Parent に渡しています
それで再レンダリングが防げるんだっけ?と思ったのですが Parent が返す ReactElement のツリーで {children} の位置が変わらないなら防げてます
例えば上記のコードだと 上側はボタンを押すたび Parent と Child がコンソールに表示されますが 下側だと Parent だけになっていて Child の再レンダリングを防げています
こういう場合には良さそうなのですが children として ReactElement を渡すところって children の表示条件や表示箇所が固定じゃなかったりします
const Parent = ({ children }) => {
console.log("Parent")
const [state, setState] = useState(0)
return (
<div>
<button onClick={() => setState(state + 1)}>{state}</button>
{state % 2 === 0 && (
<div>{children}</div>
)}
</div>
)
}
とか
const Parent = ({ children }) => {
console.log("Parent")
const [state, setState] = useState(0)
return (
<div>
<button onClick={() => setState(state + 1)}>{state}</button>
{state % 2 === 0 ? (
<div>{children}</div>
) : (
<span>{children}</span>
)}
</div>
)
}
上側はボタンを押すたびに children の表示非表示を切り替えます
非表示になると DOM の実体が消えるので 再度表示されるときに Child は再レンダリングされます
下側は常に children を表示していますがラップするタグが変わってます
親のタグが変わるだけでも同じものとして再利用されず再レンダリングされます
なのであんまり再レンダリングを防げてないんですよね
たしかに防げるケースはあるものの これで確実に防げるというものでもないです
以前 React 18 が出る前くらいにアンマウントされても state などを維持して再利用できる機能が紹介されてた気がしますが React 18 の新しいドキュメントではそれらしいコンポーネントやフックを見ないですし どうなったのでしょうね