0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】コンポーネントの複数の階層で値を受け渡しするuseContextの使い方

0
Posted at

今回は、複数の階層で値の受け渡しを行うことができるuseContextについてです。
コンテキストという技術を使えばあらかじめ上位のコンポーネントで用意されていた値を、任意の子孫コンポーネントで参照(consumeともいいます)できるようになります。

サンプルコードとして、画面の背景色を切り替える処理をuseContextで作ってみましょう。

💡 ポイント解説

createContext():コンテキストを作る(ここではテーマと切り替え関数を共有)。

useContext():どのコンポーネントでも ThemeProvider の中なら共有値を受け取れる。

ThemeProvider:アプリ全体を包んで値を供給する役割。

サンプルコード

ThemeContext.tsx
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;
}

ThemeToggler.tsx
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;

App.tsx
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でコンテキストを作る

ThemeContext.tsx
const ThemeContext = createContext<ThemeContextType | null>(null);

これは「グローバルな箱(共有スペース)」を作る関数です。
Reactのコンポーネントツリー全体で共通して使える「値を共有するためのチャンネル」を作ります。
まだ中身は null。実際の値は後でProviderが入れます。

② ThemeProvider コンポーネントを定義

ThemeContext.tsx
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 カスタムフック

ThemeContext.tsx
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 に登録されている値を“読む&使う” ことをしています。

ThemeToggler.tsx
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 なしで値を渡す」ための仕組みとなっています

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?