🐙

Reactのmemo化で再レンダリングが防げるという誤解を解く

1 min read

memo化について

Reactのコンポーネントをmemo化するとき、再レンダリングを防ぐという記述を見かけることがあります。それは誤解であり、実際にmemo化で出来るのは以下のようになものです。

  • 関数の再評価(ロジックの再実行)は防げる
  • 仮想DOMの差分比較は防げない
  • 最終的なレンダリングは確定した仮想DOMの状態次第なので、memo化に関係なく差分があるかどうかでDOM操作が決定する

Reactは仮想DOMの値に変化があった場合に、DOMを書き換える構造になっています。memo化は仮想DOMの生成結果をキャッシュしているに過ぎません。親コンポーネントが再評価されれば、子コンポーネントはmemo化の可否に関わらず差分比較の対象です。

簡単な例

ソースコード

import React, { memo, useState } from 'react';

const Test1 = memo(() => <div>Test1</div>);
const Test2 = memo(() => <div>Test2</div>);
const App = () => {
  const [value, setValue] = useState<string>();
  return (
    <>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <Test1 />
      <Test2 />
    </>
  );
};
export default App;

説明

子コンポーネントはmemo化しており、パラメータもないので再利用時に何の変化もおきません
親コンポーネントはinputのテキストが変化するごとに再評価の対象になります
さてReact Developer Toolsで、再レンダリングの対象を確認してみます

再レンダリングの対象を確認

見ての通り、親コンポーネントが変化すれば、子コンポーネントも再レンダリングの対象になります。memo化は無関係です。

再レンダリングを抑制するには

状態が変化するコンポーネントの下には、極力、子コンポーネントを置かないことです。もしくはコンポーネント間の通信をContextAPIやReduxを使って行い、親コンポーネントの変化を防ぐことが重要です。

再レンダリング抑制が本当に必要なのか考える

Reactは仮想DOMから実DOMへの差分変換を効率的に行っています。再レンダリングとは言っても、必要の無いDOM操作は行いません。小規模な画面を構築するレベルなら、効率を気にする必要の無いケースがほとんどです。

大量のデータを表示したり、コンポーネントの階層が深くなることが予見されているなら対処をとっておいた方が良いですが、そうで無いならあまり考えすぎないことをおすすめします。