個人的 React “メモ”
GAOGAO アドベントカレンダー2023 12/20の記事です。
React のレンダリング最適化においてメモ化を使わなくても十分最適化できる、と聞きつけたので、その他レンダリング最適化の手法について調べてみました。
サンプルコード
問題点:count が更新されるごとに <HeavyList>
の再レンダリングが発生する
import { useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount((prevCount) => prevCount + 1)}>
Increment
</button>
<HeavyList />
</div>
);
};
結論
Compsoition を用いる。
export default function App() {
return (
+ <Counter>
<HeavyList>
+ </Counter>
)
};
+ function Counter({ children }) {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount((prevCount) => prevCount + 1)}>
Increment
</button>
+ {children}
</div>
);
};
Comoposition とは
ReactNode 型の Props を扱うことで、これにより children としてコンポーネントを渡すことが可能となる。 ThemaProvider などでよく見かける形。
function App() {
return (
+ <ComponentA>
<ComponentB />
+ </ComponentA>
)
}
function ComponentA({children}) {
return (
<div>
+ {children}
</div>
)
}
メリット
無駄な再レンダリングを回避できる
count が更新される度に <Counter>
は再レンダリングされるが、children (<HeavyList>
) は、前回 <App>
から渡されたものと同じであるため <HeavyList>
自体は再レンダリングされない。
Props Drilling を回避できる
感想
調べてみると何年も前から提言されていることではあったし、公式ドキュメントにも記載されていた。
とはいえ RSC や React Forget に影響されて、近頃その重要性がさらに増していると思うので、このタイミングで理解を深めることができてよかった。
① RSC
RSC によって、「サーバーサイドで実行するコンポーネント」と「クライアントコンポーネントで実行するコンポーネント」を区別する。また、RSC では Client Component の中に ServerComponent を配置することができるが、これは Composition によって実現されている。
② React Forget
React では 2023 年現在 React Forget と呼ばれる最適なコンパイラーが開発されている。
React のプログラミング・モデルを維持しながら、再レンダリングのコストを最小化するために、useMemo とuseCallback 呼び出しに相当するものを自動的に生成するコンパイラーとのこと。
Discussion