レンダーとマウント — コンポーネントのライフサイクル入門
Reactのフック(useState・useEffect など)を正しく使うには、レンダーとマウントの違いを理解しておく必要があります。
この2つは混同されやすいですが、指しているものがまったく異なります。
学習者「レンダー」と「マウント」って同じ意味じゃないの…?なんとなくで使ってたけど、違うものなの?
4つの用語
| 用語 | 意味 |
|---|---|
| レンダー | コンポーネントの関数が呼ばれてUIを計算すること |
| マウント | コンポーネントが最初にDOMに追加されること |
| 再レンダー | 2回目以降のレンダー |
| アンマウント | コンポーネントがDOMから取り除かれること |
レンダーとは
レンダーとは、Reactがコンポーネント関数を呼び出してUIの計算結果(JSX)を得ることです。
function Greeting({ name }: { name: string }) {
// この関数が呼ばれること自体が「レンダー」
return <p>こんにちは、{name}さん</p>;
}レンダーのたびに関数全体が再実行されます。const・let で定義したローカル変数も、すべて作り直されます。
レンダーが起きるタイミング
- 自身の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は次の順序で処理します。
- コンポーネント関数を呼ぶ(= 初回レンダー)
- 戻り値のJSXをDOMに挿入(= マウント完了)
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回しか実行されないからです。レンダーとマウントの違いを押さえると、フックの動作が一気にわかりやすくなります。