ReactのContext APIは、プロップドリリングなしにコンポーネントサブツリー全体と値を共有できます。低頻度で広く共有されるデータに最適ですが、完全な状態管理ソリューションではなく、頻繁に変化する状態に対して再レンダリングの落とし穴があります。
なぜ重要なのか
jsx
= ();
() {
[theme, setTheme] = ();
(
);
}
Good fits (data that's read widely but changes rarely):
✓ Theme (dark/light) ✓ Current user / auth
✓ Locale / i18n ✓ App-wide config or feature flags
// ❌ a context value that changes often re-renders ALL consumers
const AppContext = createContext();
// value = { user, cart, notifications, ...everything }
// → updating ONE field re-renders EVERY component using the context
Context値が変更されると、変更された部分を使用しているかどうかに関わらず、そのContextを消費するすべてのコンポーネントが再レンダリングされます。頻繁に更新される状態の場合、これはパフォーマンスの問題を引き起こします。Contextには組み込みの選択的なサブスクリプションがありません。
✓ Split into multiple focused contexts (ThemeContext, UserContext separately)
✓ Memoize the value object (useMemo) so it doesn't change identity needlessly
✗ But for high-frequency or large shared state → use a real store
状態管理ライブラリ(Zustand、Redux、Jotai)は選択的なサブスクリプションで再レンダリング問題を解決します — コンポーネントは使用するスライスのみにサブスクライブし、それらが変更された場合のみ再レンダリングします:
const count = useStore(s => s.count); // re-renders ONLY when count changes
Context = a TRANSPORT mechanism (passes a value down), NOT state management itself.
You still need useState/useReducer to hold the state; Context just distributes it.
Contextの得意分野とその限界を知ることで、2つの一般的な間違いを防ぎます:Contextに入るべきものをプロップドリリングすること、および高頻度の状態をContextに入れること(アプリ全体の再レンダリングを引き起こす)。
ルール:Context用にめったに変わらず、広く共有される値(テーマ、ユーザー、ロケール)を使用します。頻繁に変わるまたは大規模な共有状態には選択的なサブスクリプション付きの専用ストアを使用します。
Contextが状態を配布するが管理しないことを理解すると、それで十分な場合と更に必要な場合が明確になります。