今回は、複数の階層で値の受け渡しを行うことができるuseContextについてです。
コンテキストという技術を使えばあらかじめ上位のコンポーネントで用意されていた値を、任意の子孫コンポーネントで参照(consumeともいいます)できるようになります。
サンプルコードとして、画面の背景色を切り替える処理をuseContextで作ってみましょう。
💡 ポイント解説
createContext():コンテキストを作る(ここではテーマと切り替え関数を共有)。
useContext():どのコンポーネントでも ThemeProvider の中なら共有値を受け取れる。
ThemeProvider:アプリ全体を包んで値を供給する役割。
サンプルコード
import React,{ createContext,useContext,useState } from "react";
// テーマの型
type Theme = 'light' | 'dark';
// Contextで共有したい値の型
type ThemeContexttype = {
theme:Theme;
toggleTheme:()=>void;
}
// Contextの作成(デフォルト値は null)
const ThemeContext = createContext<ThemeContexttype | null>(null);
// Providerコンポーネント
export const ThemeProvider:React.FC<{ children:React.ReactNode }> = ({ children })=>{
const [theme,setTheme] = useState<Theme>('light');
const toggleTheme = ()=>{
setTheme((prev)=>(prev === 'light' ? 'dark':'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Contextを簡単に使うためのカスタムフック
export const useTheme = ()=>{
const context = useContext(ThemeContext);
if(!context) throw new Error('useTheme must be used within a ThemeProvider');
return context;
}
import React from 'react';
import { useTheme } from './ThemeContext';
const ThemeToggler:React.FC = ()=>{
const { theme,toggleTheme } = useTheme();
const styles = {
backgroundColor: theme === 'light' ? '#fff' : '#222',
color: theme === 'light' ? '#000' : '#fff',
height: '100vh',
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.3s ease',
};
return (
<div style={styles}>
<h1>現在のテーマ: {theme}</h1>
<button onClick={toggleTheme}>テーマ切り替え</button>
</div>
);
}
export default ThemeToggler;
import './App.css';
import { ThemeProvider } from './ThemeContext';//追加
import ThemeToggler from './ThemeToggler';
function App() {
return (
<div>
<h1 data-testid="app-title">My React App</h1>
<ThemeProvider>
<ThemeToggler />
</ThemeProvider>
</div>
);
}
export default App;
解説
全体の構成イメージ
ThemeProvider が「アプリ全体にテーマ情報を配る」
ThemeToggler が「そのテーマ情報を受け取って使う」
という関係になっています。
まず ThemeContext.tsx では何をしているか?
ここでContextの“定義と供給” をしています。
順を追って見ていきましょう👇
①createContextでコンテキストを作る
const ThemeContext = createContext<ThemeContextType | null>(null);
これは「グローバルな箱(共有スペース)」を作る関数です。
Reactのコンポーネントツリー全体で共通して使える「値を共有するためのチャンネル」を作ります。
まだ中身は null。実際の値は後でProviderが入れます。
② ThemeProvider コンポーネントを定義
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState<Theme>('light');
const toggleTheme = () => {
setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
ここでやっていること
1.useState で theme(ライト or ダーク)を管理
→ theme が「今のテーマ情報」。
2.toggleTheme でテーマを切り替える関数を用意。
3.ThemeContext.Provider に value={{ theme, toggleTheme }} を渡す。
→ これがコンテキストに「共有する実際のデータ」です。
4.{children} によって、Provider で囲まれた下のコンポーネントすべてが、この値を受け取れるようになります。
つまり、
ThemeProvider は「値を配る親コンポーネント(Provider)」です。
③ useTheme カスタムフック
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme must be used within a ThemeProvider');
return context;
};
useContext(ThemeContext) で、現在のコンテキストの値を取得します。
これを使えば、どのコンポーネントでも簡単にテーマ情報を取り出せます。
次に ThemeToggler.tsx では何をしているか?
ここでは ThemeContext に登録されている値を“読む&使う” ことをしています。
import { useTheme } from './ThemeContext';
const ThemeToggler: React.FC = () => {
const { theme, toggleTheme } = useTheme(); // ← ここでテーマ情報を取得!
const styles = {
backgroundColor: theme === 'light' ? '#fff' : '#222',
color: theme === 'light' ? '#000' : '#fff',
height: '100vh',
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.3s ease',
};
return (
<div style={styles}>
<h1>現在のテーマ: {theme}</h1>
<button onClick={toggleTheme}>テーマ切り替え</button>
</div>
);
};
ここでやっていること
1.useTheme() で、ThemeProvider が提供している { theme, toggleTheme } を受け取る。
2.受け取った theme に応じて背景や文字色を変える。
3.ボタンを押すと toggleTheme() が呼ばれ、ThemeProvider 側の useState が更新される。
4.それにより、全てのコンポーネントが自動的に再レンダリングされ、テーマが変わる。
まとめ(データの流れ)
ThemeProvider(上位)
├─ useState で theme 状態を保持
├─ toggleTheme() で更新する関数を定義
├─ value = { theme, toggleTheme } を Provider に渡す
│
▼
ThemeToggler(下位)
├─ useTheme() 経由で value を受け取る
├─ theme を使って画面を描画
└─ toggleTheme() を呼んで上位の状態を更新
つまり、useContext は:
「親コンポーネントから深い階層の子コンポーネントに、props なしで値を渡す」ための仕組みとなっています