ウェブエンジニア問題集

レンダーとマウント — コンポーネントのライフサイクル入門

Reactのフック(useStateuseEffect など)を正しく使うには、レンダーマウントの違いを理解しておく必要があります。 この2つは混同されやすいですが、指しているものがまったく異なります。

学習者学習者

「レンダー」と「マウント」って同じ意味じゃないの…?なんとなくで使ってたけど、違うものなの?


4つの用語

用語意味
レンダーコンポーネントの関数が呼ばれてUIを計算すること
マウントコンポーネントが最初にDOMに追加されること
再レンダー2回目以降のレンダー
アンマウントコンポーネントがDOMから取り除かれること

レンダーとは

レンダーとは、Reactがコンポーネント関数を呼び出してUIの計算結果(JSX)を得ることです。

function Greeting({ name }: { name: string }) {
  // この関数が呼ばれること自体が「レンダー」
  return <p>こんにちは、{name}さん</p>;
}

レンダーのたびに関数全体が再実行されます。constlet で定義したローカル変数も、すべて作り直されます。

レンダーが起きるタイミング

  • 自身のstateが変わったときuseState の更新関数を呼んだとき)
  • 親コンポーネントが再レンダーされたとき(子も連動して再実行される)
function Counter() {
  const [count, setCount] = useState(0);
 
  console.log('rendered'); // ボタンを押すたびにここが実行される
 
  return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}

ボタンを押すたびに Counter 関数が再実行され、console.log('rendered') が出力されます。


マウントとは

マウントとは、コンポーネントが初めてDOMに挿入されることです。ライフサイクル中に1回だけ起きます。

マウントは「初回レンダー + DOMへの挿入」の組み合わせです。

マウント = 初回レンダー + DOMへの挿入

コンポーネントがページに表示されるとき、Reactは次の順序で処理します。

  1. コンポーネント関数を呼ぶ(= 初回レンダー)
  2. 戻り値のJSXをDOMに挿入(= マウント完了)
  3. useEffect のコールバックを実行(マウント後)

再レンダーとアンマウント

再レンダー — stateやpropsの変化をきっかけに、マウント後に繰り返されるレンダーです。DOMへの挿入は最初の1回だけで、再レンダーではReactが差分だけを更新します。

アンマウント — コンポーネントが画面から取り除かれることです。条件分岐({show && <Component />})やルート遷移などで発生します。アンマウント時に useEffect のクリーンアップ関数が実行されます。


全体の流れ


コードで確認する

function Counter() {
  const [count, setCount] = useState(0);
 
  // レンダーのたびにここが実行される(初回 + 再レンダー)
  console.log('rendered');
 
  useEffect(() => {
    // マウント時に1回だけ実行される
    console.log('mounted');
 
    return () => {
      // アンマウント時に実行される
      console.log('unmounted');
    };
  }, []);
 
  return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}

ボタンを3回押したときのコンソール出力:

rendered   ← 初回レンダー(マウント時)
mounted    ← マウント完了後
rendered   ← 再レンダー(1回目)
rendered   ← 再レンダー(2回目)
rendered   ← 再レンダー(3回目)

rendered は計4回(初回 + 3回)、mounted は1回だけです。コンポーネントが画面から消えるとき(アンマウント)に unmounted が出力されます。


useEffectとの関係

この違いが useEffect の依存配列と直接つながります。

// 依存配列なし → 毎レンダー後に実行(再レンダーのたびにも走る)
useEffect(() => {
  console.log('every render');
});
 
// 空配列 → マウント時に1回だけ実行
useEffect(() => {
  console.log('mount only');
}, []);

「依存配列なし」と「空配列 []」は見た目が似ていますが、前者は毎レンダー後に実行され、後者はマウント時のみです。この違いはレンダーとマウントの概念を理解していれば自然に納得できます。

詳しくは「useEffect — 副作用と外部同期」で解説しています。


まとめ

  • レンダー — コンポーネント関数の実行。stateやpropsの変化のたびに何度でも起きる。
  • マウント — 初回レンダー + DOMへの挿入。ライフサイクル中に1回だけ。
  • 再レンダー — 2回目以降のレンダー。DOMは差分だけ更新される。
  • アンマウント — コンポーネントがDOMから取り除かれるとき。

useEffect(..., []) が「マウント時のみ」と言われるのは、空配列だと何にも反応しないため最初の1回しか実行されないからです。レンダーとマウントの違いを押さえると、フックの動作が一気にわかりやすくなります。