第8回
useMemoでパフォーマンス最適化:重い計算をメモ化する
ReactのuseMemoを解説します。メモ化の仕組み・高コスト計算の最適化・参照の安定化、そしてuseMemoを使うべき場面・使わなくてよい場面の判断基準を実例付きで学べます。
制作・運営:React Guide 運営者
計算結果を再利用できる条件
useMemo は、依存が前回と同じなら計算結果を再利用するための最適化です。stateやpropsの代わりではありません。外しても正しく動作するコードに使います。
フィルター文字を変えるたびに再計算が必要なら、その更新の計算量はuseMemoだけでは減りません。無関係な入力による再計算を省けるかを分けて考えます。
無関係な入力と検索を分けて試す
以下を src/App.tsx に置きます。大量のデータや外部APIを使わず、再計算する条件を確認する例です。速度改善の実測例ではありません。
import { useMemo, useState } from 'react'
const products = [
{ id: 'pen', name: '青いペン' },
{ id: 'note', name: '青いノート' },
{ id: 'bag', name: '赤いかばん' },
]
export default function App() {
const [query, setQuery] = useState('')
const [note, setNote] = useState('')
const filtered = useMemo(() => {
console.log('商品を絞り込み')
return products.filter(p => p.name.includes(query))
}, [query])
return (
<main>
<label>検索<input value={query} onChange={e => setQuery(e.target.value)} /></label>
<label>メモ<input value={note} onChange={e => setNote(e.target.value)} /></label>
<ul>{filtered.map(p => <li key={p.id}>{p.name}</li>)}</ul>
</main>
)
}productsはモジュールで定義した固定データなので、変化する依存はqueryだけです。productsをpropsで受け取るなら [products, query] にします。noteの更新では同じ結果を使い、queryの更新では絞り直します。
StrictModeでは計算関数を追加で実行する場合があります。調査用ログを除き、計算関数は副作用を持たせず純粋にしてください。この3件程度の検索では、実際にはuseMemoなしで十分です。
sortは元の配列を変更する
// コンポーネント内の抜粋。recordsはprops。
const sorted = useMemo(
() => [...records].sort((a, b) => b.amount - a.amount),
[records],
)records.sort(...) はpropsそのものを変更します。コピーしてから並べ替える点は、メモ化の有無にかかわらず必要です。親が毎回新しいrecords配列を渡せば、内容が同じでも再計算されます。
子の再レンダーを省く用途
memoで包んだ子へ配列を渡す場合も、同じ配列を再利用することが役立ちます。ただし、他のpropsが変わる、子自身のstateが変わる、購読するContextが変わる場合には、子は再レンダーされます。
Effectのためだけにオブジェクトを固定したいなら、先にEffect内でオブジェクトを作れないか考えます。キャッシュが維持されることを、接続の正しさの条件にしないでください。
使うか決める手順
- 同じデータ・端末・操作で、遅い処理をProfilerなどで測ります。
- 計算の入力が変わらない更新が多いかを確認します。
- useMemoを入れて同じ条件で比べます。値が毎回変わるならキャッシュの効果は小さくなります。
軽い計算では管理コストや読みづらさが増えることがあります。一律に速くなる、遅くなるとは決めません。React Compilerを有効にしたプロジェクトでは自動メモ化もあるため、手書きの追加前に適用状況を確認します。
同じテーマの教材
useTransitionとuseDeferredValue:入力と一覧の更新を分ける
検索入力と一覧の更新を分けるサンプルでuseTransitionとuseDeferredValueを解説します。更新の優先度、memoとの関係、別スレッドや通信の間引きとの違いを確認します。
useCallbackで関数をメモ化:React.memoと組み合わせた最適化
ReactのuseCallbackを解説します。関数のメモ化・React.memoとの組み合わせ・useEffectの依存配列での活用を実例で解説。useMemoとの違いと使い分けも明確にします。
React Compiler 1.0:Viteへの導入とメモ化の確認方法
安定版になったReact Compilerを実際に試す。Vite 8環境への導入からDevToolsでの効果確認、既存のuseMemoとの付き合い方までを動かしながら解説する。