useContextについて

## React Contextとは？
React Contextは、コンポーネント間で共有したいデータを効率的に管理・提供する仕組みです。通常、データは`props`を使って親コンポーネントから子コンポーネントへ手渡しで渡します。しかし、ツリー構造が複雑になると、データを渡すために中間のコンポーネントにもプロップスを渡さなければならない「プロップスドリリング」という問題が発生します。

`Context`を使うと、親から子へ直接データを渡す必要がなくなり、どのコンポーネントからでもそのデータへアクセスできるようになります。データの共有がシンプルになり、コードがわかりやすくなるのです。なお、`Context`は、`props`とは別の方法でコンポーネントに動的に値を渡す、React純正のAPIです。

## useContextとは？
React Hooksの1つで、グローバルにデータを管理することができる仕組みです。コンポーネント間のデータ共有を簡単にします。

例えば、

**テーマの切り替え**
ライトモード、ダークモードなど使用するテーマを管理するために、`Context`を使用できます。コンポーネント内でテーマを設定する代わりに、テーマ情報を`Context`に保存し、アプリ全体で使用できるようにします。

**言語設定の切り替え**
多言語をサポートする場合、言語設定を`Context`に保存し、アプリ内の複数のコンポーネントで共有できます。

<font color="#66FF00">**グローバルな状態の管理**</font>
アプリ全体で使用する設定やデータをグローバルに管理するため`Context`を使用することができます。共有するAPIキー、データベースの接続情報、ユーザーのお気に入りアイテムなどです。

※必ずしも全ての状態をグローバルに管理する必要は無く、また`useContext`でなくとも同じような実装ができる機能はあるので、事前に必要な状態を考え、適切に設計することが重要とのことです。経験値から判断できるようになるのではないかと思ってます。

## 基本的な記述
```parent.jsx
// createContextをインポート
import React, { createContext } from 'react';

// createContext()を使用し、コンテキストの定義
// 引数には、propsを通さずに渡したい値を記述
export const TestContext = createContext("useContextの使い方");

// 定義したcontext(TestContext)のProviderというコンポーネントで
// stateを使用するコンポーネントを囲います
// valueにセットされた値がuseContextを通して
// ネストされたコンポーネントで取得することができるようになる
<TestContext.Provider value={[value, setValue]}> 
  <Child />
</TestContext.Provider>
```
```child.jsx
// useContextをインポート
import { useContext } from "react";

// value = useContextの使い方
const value = useContext(TestContext);
```

## 使用例 (テーマの切り替え)
[codesandbox](https://codesandbox.io)などでサクッと試せる内容です。
以下のファイルを作成します。
```
src
├ App.jsx
├ ThemedButton.jsx
┗ ThemeProvider.jsx
```
```App.jsx
import "./styles.css";
import { ThemeProvider } from "./ThemeProvider";
import ThemedButton from "./ThemedButton";

export default function App() {
  return (
    <ThemeProvider>
      <div style={{ textAlign: "center", marginTop: "50px" }}>
        <h1>テーマの切り替え</h1>
        <ThemedButton />
      </div>
    </ThemeProvider>
  );
}
```
```ThemeProvider.jsx
import React, { createContext, useState } from "react";

// ThemeContextを作成
const ThemeContext = createContext();

// ThemeProviderコンポーネントを作成
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light"); // 初期テーマは 'light'
  
  // テーマを切り替え
  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light")); 
  };

  return (
  // Providerコンポーネントで包むことによって、Provider配下のコンテキストを決定する
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export { ThemeContext, ThemeProvider };
```
```ThemedButton.jsx
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeProvider";

function ThemedButton() {
  // useContext でコンテキストからテーマとテーマを切り替える関数を取得
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button
      onClick={toggleTheme}
      style={{
        backgroundColor: theme === "light" ? "#fff" : "#333",
        color: theme === "light" ? "#000" : "#fff",
        padding: "10px 20px",
        border: "none",
        borderRadius: "5px",
      }}
    >
      テーマ : {theme}  {/*light, dark*/}
    </button>
  );
}

export default ThemedButton;
```
![スクリーンショット 2024-10-20 3.05.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/cc3e9544-f9ad-c848-49aa-a139e89285f6.png)