React で再レンダリングが多くて重いとき、どう直しますか

勘で memo を足さず、まず Profiler で原因の部品を見つける、と答える問い。state を使う場所の近くへ下げる、memo と useMemo と useCallback、長い一覧の仮想スクロールまで、順に話します。

答えてみる

面接官に「React で再レンダリングが多くて重いとき、どう直しますか」と聞かれたつもりで、答えを見る前に自分の言葉で答えます。

声に出して答えた人は「書かずに答えを見る」で開けます。

解説を読む

聞かれ方から関連するコースまで、この問いの解説を全部ここに置いています。

こう聞かれます

  • 「React で再レンダリングが多くて重いとき、どう直しますか」
  • 「memo、useMemo、useCallback は、いつ使いますか」
  • 「何千件もある一覧が重いと言われました。どうしますか」

面接官が見ている点

  • いきなり memo を付けて回らず、まず測って原因の部品を特定する、と言えるか
  • 再レンダリングが起きる条件 (自分の state が変わる、親が描き直される) を分かっているか
  • state を使う場所の近くへ下げる、という作りの直しを先に考えられるか
  • 長い一覧は、見えている分だけ描く (仮想スクロール) という手を知っているか

短い答え

  • まず React DevTools の Profiler で、どの部品が何度、どれだけ時間をかけて描き直されているかを測り、原因を特定します。
  • 次に、state を使う部品の近くまで下げて、関係ない部品が巻き込まれないようにし、それでも重い所だけ memo、useMemo、useCallback を使います。
  • 何千件もの一覧は、画面に見えている分だけを描く仮想スクロールにします。memo は比べる手間が増えるので、測って効く所にだけ付けます。

少し詳しい答え

再レンダリングが起きる条件

再レンダリングとは、React が部品の関数をもう一度呼んで、画面を描き直すことです。主に次のときに起きます。

  • その部品の state が変わった
  • 親の部品が描き直された (子は、props が変わっていなくても、既定では一緒に描き直されます)
  • 使っている Context の値が変わった

描き直し自体は悪いことではありません。React は、描き直した結果を前と比べて、本当に変わった所だけを画面に反映します。困るのは、重い計算や大きな一覧を、要らないのに何度も描き直すときです。

まず測る

React DevTools の Profiler で操作を記録すると、どの部品が何回、どれだけの時間で描き直されたかが見えます。「1 文字打つたびに、関係ない一覧まで全部描き直している」のような原因が分かってから直します。

直す順番

いちばん効くことが多いのは、state を使う場所の近くへ下げることです。

TypeScript (JSX)

// 直す前 入力の state を親が持つので、打つたびに一覧も描き直される
function Page() {
  const [text, setText] = useState("");
  return (
    <>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <BigList />
    </>
  );
}

// 直した後 入力の state を入力の部品に閉じ込める
function SearchBox() {
  const [text, setText] = useState("");
  return <input value={text} onChange={(e) => setText(e.target.value)} />;
}

function Page() {
  return (
    <>
      <SearchBox />
      <BigList />
    </>
  );
}

それでも重いときに、メモ化 (前と同じ入力なら前の結果を使い回すこと) を使います。

  • memo props が前と同じなら、その部品の描き直しを飛ばします
  • useMemo 重い計算の結果を、依存配列の値が変わるまで覚えておきます
  • useCallback 関数を毎回作り直さず、同じ物を渡します。memo を付けた子に関数を渡すときに意味があります

何千件もの一覧は、画面に見えている数十件だけを描き、スクロールに合わせて入れ替える仮想スクロールにします (react-window や TanStack Virtual などの道具があります)。

トレードオフ

memo や useMemo は、前の値と比べる手間と、覚えておくメモリを使います。軽い部品に全部付けると、かえって遅くなったり、コードが読みにくくなったりします。依存配列を書き間違えると、古い値のまま画面が変わらない不具合も生みます。だから、作りの直し (state を下げる、部品を分ける) を先にし、測って効く所にだけ付けます。

仮想スクロールにも弱点があり、ページ内検索で見えていない行が引っかからない、行の高さがばらばらだと扱いが難しい、などがあります。数百件程度で重くないなら、ふつうに描くほうが単純です。

話すときは、自分が直した画面の例と、直す前と後で測った値を 1 つ用意します。

よくある間違い

  • 測らずに memo を全部に付ける比べる手間が増え、効かないこともあります。Profiler で原因を見てから直します
  • state を上の部品に置きすぎる 1 つの入力のために、ページ全体が描き直されます。使う部品の近くへ下げます
  • useCallback だけ付けて、子に memo が無い子は親と一緒に描き直されるので、関数を同じにしても効きません

深掘りの問い

  • 「Context の値が変わると、何が描き直されますか」その Context を使う部品が全部描き直されるので、変わる頻度の違う値は別の Context に分ける、と答えます
  • 「一覧の key に配列の番号を使うと、何が困りますか」 並べ替えや削除のときに、React が別の行を同じ物と思い込み、入力の中身がずれたり余計に描き直したりする、と答えます
  • 「描き直しの回数より、1 回が重いときは」重い計算を useMemo で覚える、サーバーで先に計算しておく、画面に出す量を減らす、を挙げます

確認日 2026年10月24日

技術面接問題の一覧へ戻る