0Pricing
React Academy · レッスン

再レンダーを抑えるためのContext分割

頻繁に変化する値と安定した値を別々のContextに分離します。

「再レンダーを抑えるためのContext分割」はCoddyKit上の無料React Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。

ようこそ

このレッスンでは、コンテキスト値の一部だけが変化したときの再レンダリングを最小限に抑えるため、React Context を別々のプロバイダーに分割する方法を学びます。

Context による再レンダリングの問題

useContext(MyCtx) を呼び出すすべてのコンポーネントは、コンテキスト値の ANY の部分が変化すると再レンダリングされます。使用している部分が変化していなくても同様です。大きなコンテキストを 1 つだけ使うと、不要な再レンダリングが多数発生する可能性があります。

更新頻度による分割

頻繁に変化する値と、ほとんど変化しない値を分けます。それぞれのグループを独自のコンテキストに配置します。コンシューマーは必要なコンテキストだけを購読します。
const ThemeCtx = createContext('light');
const UserCtx = createContext(null);
// theme changes rarely; user changes on login/logout — same frequency is fine
// but notifCount changes every second — split it out!

データとディスパッチコンテキストの分離

よく使われるパターンは、state データ用のコンテキスト(変更のたびに再レンダリングされる)と、dispatch/setter 関数用のコンテキスト(安定しており、コンシューマーを再レンダリングしない)に分ける方法です。dispatch だけを使うコンシューマーは、データが変化しても再レンダリングされません。
const CountCtx = createContext(0);
const SetCountCtx = createContext(() => {});

function Provider({ children }) {
  const [count, setCount] = useState(0);
  return (
    <CountCtx.Provider value={count}>
      <SetCountCtx.Provider value={setCount}>
        {children}
      </SetCountCtx.Provider>
    </CountCtx.Provider>
  );
}

ディスパッチコンテキストのメモ化

useState の setter はすべてのレンダリングで同じ参照を持つため安定しています。そのため、ディスパッチコンテキストの値は変化しません。ただし、アクションのオブジェクトを作成する場合は useMemo でラップします。
const actions = useMemo(() => ({
  increment: () => setCount(c => c + 1),
  reset: () => setCount(0),
}), []); // stable — empty deps

ネストしたプロバイダー

コンポーネントツリー内に複数のプロバイダーをネストします。コンシューマーは必要な特定のコンテキストだけを import して使用するため、購読範囲を狭く保てます。
function App() {
  return (
    <AuthProvider>
      <ThemeProvider>
        <NotificationsProvider>
          <Router />
        </NotificationsProvider>
      </ThemeProvider>
    </AuthProvider>
  );
}

分割前のプロファイリング

コンテキストを分割する前に、必ず React DevTools でプロファイリングします。不要な再レンダリングが問題になるのは、それにコストがかかる場合だけです。再レンダリングが高速なコンテキストを過剰に設計しないでください。

コンテキスト分割のトレードオフ

コンテキストを増やすと、コンポーネントツリー内のプロバイダーも増えます。その結果、理解すべきことが増えます。事前に分割するのではなく、プロファイリングでパフォーマンスの問題が確認された場合にだけ分割してください。

React.memo との組み合わせ

コンテキストが 1 つだけでも、コストの高い子コンポーネントを React.memo でラップすれば、props が変化したときだけ再レンダリングされます。コンテキストが変化しただけでは再レンダリングされません。これは、分割よりも簡単な代替手段になる場合があります。
const ExpensiveChild = React.memo(function({ label }) {
  return <div>{label}</div>;
}); // won't re-render on context change if label hasn't changed

useReducer と Context

複雑な state を管理するには、useReducer とコンテキストを組み合わせます。state は 1 つのコンテキストに、dispatch 関数は別のコンテキストに保存します。dispatch は安定していますが、state はアクションごとに更新されます。

理解度チェック

state と dispatch を別々のコンテキストに分けると、なぜパフォーマンスが向上するのでしょうか?

まとめ

更新頻度に応じてコンテキストを分割します。頻繁に変化する state は 1 つのコンテキストに、安定した dispatch/setter は別のコンテキストに配置します。まずプロファイリングを行い、必要な場合だけ分割し、より簡単な代替手段として React.memo も検討します。

次のレッスン

次のレッスンは **Memoizing Context Values with useMemo** です。コンテキスト値のオブジェクトを useMemo でラップし、データが変化していないときにコンシューマーが再レンダリングされないようにします。

よくある質問

「再レンダーを抑えるためのContext分割」レッスンは無料ですか?

はい。「再レンダーを抑えるためのContext分割」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。

「再レンダーを抑えるためのContext分割」で何を学びますか?

頻繁に変化する値と安定した値を別々のContextに分離します。 ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

React Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「再レンダーを抑えるためのContext分割」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このReact Academyレッスンでコードを書いて実行できますか?

はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 再レンダーを抑えるためのContext分割
  2. useMemoによるContext値のメモ化
  3. Context Selectorパターン
  4. Contextを使わないケース
← React Academyに戻る