Reactの再レンダリングとメモ化の話

公開日:

タグ:

  • #Next.js
  • #React

Reactのレンダリングについてあまり理解できておらず、曖昧なまま使っていた部分もあったので、改めて調べ直しました。


Reactが再レンダリングを行うタイミングは3つ

そもそも、Reactが再レンダリングが行われるパターンは3つしかありません。

1. stateが変わった時

'use client';

import { useState } from 'react';
import styles from './page.module.scss';

export default function Parent() {
  console.log('Parent component rendered');
  const [text, setText] = useState('');

  return (
    <>
      <h2 className={styles.title}>Re-Rendered</h2>
      <input
        className={styles.input}
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
    </>
  );
}

上記の場合 text が更新されるたびに再レンダリングが走ります。

2. propsが変わった時

'use client';
import { Child } from '@/components/Child';

import { useState } from 'react';
import styles from './page.module.scss';

export default function Parent() {
  console.log('Parent component rendered');
  const [count, setCount] = useState(0);

  return (
    <>
      <h2 className={styles.title}>Re-Rendered</h2>
      <button
        className={styles.button}
        type="button"
        onClick={() => setCount(count + 1)}
      >
        Increment Count
      </button>
      <Child count={count} />
    </>
  );
}
export const Child = ({ count }: { count: number }) => {
  console.log('Child component rendered');
  return <div>{count}</div>;
};

親コンポーネントで Child コンポーネントに count という値を渡している。なので、 count が変更されると Child が再レンダリングされる。

3. 親が再レンダリングした時

'use client';
import { Child } from '@/components/Child';

import { useState } from 'react';
import styles from './page.module.scss';

export default function Parent() {
  console.log('Parent component rendered');
  const [count, setCount] = useState(0);

  return (
    <>
      <h2 className={styles.title}>Re-Rendered</h2>
      <button
        className={styles.button}
        type="button"
        onClick={(e) => setCount(count + 1)}
      >
        Increment Count
      </button>
      <Child />
    </>
  );
}
export const Child = () => {
  console.log('Child component rendered');
  return <div>Child Component</div>;
};

上記の例では、 Childコンポーネントには props を渡していません。ですが、 Parentコンポーネントで

state を更新しているため、親コンポーネントの再レンダリングに合わせて、Childコンポーネントも再レンダリングされます。

メモ化とは

この「不要な再レンダリング」を防ぐために、Reactにはメモ化という仕組みがあります。

メモ化とは簡単に言うと、

前回と同じ結果になるのであれば、処理をスキップする

という最適化の考え方です。

今回の例でいうと、3番目の親が最レンダリングされることで子も再レンダリングパターンです。

  • Child は props を受け取っていない
  • 表示内容も変わっていない

このような「見た目が変わらないのに再レンダリングされるコンポーネント」に対して、

  • 前回と状態が変わっていないなら再レンダリングしない

という仕組みを使えるのが、Reactのメモ化です。

React では次のような方法でメモ化を行います。

  • React.memo:コンポーネントの再レンダリングをスキップする
  • useMemo:値の再計算を防ぐ
  • useCallback:関数の再生成を防ぐ

ただし、これらは「再レンダリングを完全に止める」ためのものではなく、

必要な再レンダリングだけを残し、不要なものを減らすための最適化

という位置づけの仕組みです。

詳しい内容はまた次回。

参考URL

一覧へ戻る