ReactのuseContext入門:コンポーネント間で状態を共有する
useContextとは
useContext はコンポーネントツリーを通じて値を共有するためのフックです。propsのバケツリレー(中間のコンポーネントを経由してpropsを渡し続ける問題)を解決できます。
propsのバケツリレーとは
// 問題:Buttonに渡したいだけなのにMiddleでも受け取る必要がある function App() { const [theme, setTheme] = useState('dark') return <Middle theme={theme} /> } function Middle({ theme }: { theme: string }) { return <Button theme={theme} /> // 自分では使わないのに渡している } function Button({ theme }: { theme: string }) { return <button className={theme}>Click</button> }
Contextで解決する
1. Contextを作成する
import { createContext, useContext, useState } from 'react' type ThemeContextType = { theme: string setTheme: (theme: string) => void } const ThemeContext = createContext<ThemeContextType | null>(null)
2. Providerで値を提供する
function App() { const [theme, setTheme] = useState('dark') return ( <ThemeContext.Provider value={{ theme, setTheme }}> <Middle /> </ThemeContext.Provider> ) }
3. useContextで値を取得する
function Button() { const ctx = useContext(ThemeContext) if (!ctx) return null return ( <button className={ctx.theme} onClick={() => ctx.setTheme('light')} > テーマ切替 </button> ) }
中間の Middle はpropsを一切受け取らずに済みます。
カスタムフックで使いやすくする
useContext を毎回 null チェックするのは面倒なので、カスタムフックにまとめるのが一般的です。
function useTheme() { const ctx = useContext(ThemeContext) if (!ctx) throw new Error('useTheme must be used within ThemeProvider') return ctx } // 呼び出し側がシンプルになる function Button() { const { theme, setTheme } = useTheme() return <button className={theme}>Click</button> }
Providerを分離してコンポーネントを整理する
function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState('dark') return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ) } // App がすっきりする function App() { return ( <ThemeProvider> <Middle /> </ThemeProvider> ) }
useContextで管理するのが向いているもの
| 向いている | 向いていない |
|---|---|
| テーマ(ダーク/ライト) | 頻繁に更新される状態 |
| ログインユーザー情報 | 複雑な非同期処理 |
| 言語設定(i18n) | 大規模なグローバル状態 |
| モーダルの開閉状態 | — |
Contextは再レンダリングの最適化が難しいため、更新頻度が高い状態や大規模なアプリには Redux Toolkit や TanStack Query が向いています。
まとめ
| 手順 | コード |
|---|---|
| Contextを作成 | createContext<型>(初期値) |
| 値を提供 | <Context.Provider value={...}> |
| 値を取得 | useContext(Context) |
useContextは小〜中規模のグローバル状態共有に適している- カスタムフック化するとコードが整理される
- 大規模・高頻度更新は Redux Toolkit を検討する
Reactのプロジェクト作成から始める場合は「React + Vite でプロジェクト作成」を参照してください。
状態管理の基本は「ReactのuseState入門」を、複雑な状態遷移には「ReactのuseReducer入門」を、アプリ全体のグローバル状態管理には「Redux Toolkit 入門」を参照してください。