React hooksを理解する（useContext）

## 目次

- Context とは？
- useContext の基本的な使い方
- useContext を使うメリット
- 実践例
- useContext の注意点
- まとめ

## Contextとは？

Reactの**Context**は、ツリー状のコンポーネント全体でデータを共有する仕組みです。

通常、Reactでは**props**を使ってデータを親コンポーネントから子コンポーネントに渡しますが、Contextを使うとどの階層にあるコンポーネントでも直接データを取得 できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/e0a096e9-12c5-73e3-d662-35cab1a44abf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/14904785-ae51-e656-20af-03ae35ea2950.png)


#### Context の主な特徴
- データの「グローバルな状態管理」が簡単になる
- 子コンポーネントでpropsを繰り返し渡す必要がなくなる
- 状態やテーマ設定、認証情報などをコンポーネント全体で共有しやすい

## useContextの基本的な使い方

#### 1. Contextを作成

以下に、テーマを切り替えるためのThemaContextを作成し、使用する例を示します。

```jsx

import React, { createContext, useState, useContext } from "react";

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

```

#### 2. Context を提供 (Provider)

ThemeProvider Componentは、ThemeContext.Provider を使ってContextの値を設定し、提供します。
このContextは、テーマに関するデータ（theme）と、テーマを切り替える関数（toggleTheme）を持ちます。

```jsx

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  // テーマを切り替える関数
  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
  };

  // Context に渡す値を指定
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

```

childrenをラップすることで、どのComponentでもContextの値にアクセスできるようになります。

#### 3. Contextを消費 (UseContext)
useContextフックを使うことで、Contextの値を直接取得します。

```jsx

function ThemeSwitcher() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" }}>
      <p>現在のテーマ: {theme}</p>
      <button onClick={toggleTheme}>テーマを切り替え</button>
    </div>
  );
}

```

#### 4. アプリ全体で使用する

```jsx

function App() {
  return (
    <ThemeProvider>
      <ThemeSwitcher />
    </ThemeProvider>
  );
}

export default App;

```

## useContextを使うメリット

#### 1. props を繰り返し渡す必要がない
子や孫コンポーネントにデータを渡すとき、親から順番にpropsを伝播させる必要がなくなる

#### 2. コードがシンプルに
useContext を使うと、直接必要な値を取得できるため、コードが簡潔になる

#### 3. グローバルな状態管理
コンポーネント間で共通のデータ（例: ユーザー情報、テーマ設定など）を管理しやすい

## 実践例

ここでは、カートのアイテム数を Context で管理する例を紹介します。

#### Contextの作成

```jsx

import React, { createContext, useState, useContext } from "react";

// カートの Context を作成
const CartContext = createContext();

```

#### Providerの作成

```jsx

function CartProvider({ children }) {
  const [cartItems, setCartItems] = useState([]);

  // アイテムを追加する関数
  const addToCart = (item) => {
    setCartItems([...cartItems, item]);
  };

  return (
    <CartContext.Provider value={{ cartItems, addToCart }}>
      {children}
    </CartContext.Provider>
  );
}

```

#### カートを表示するコンポーネントでContextを使う

```jsx

function Cart() {
  const { cartItems } = useContext(CartContext);

  return (
    <div>
      <h2>カートの中身:</h2>
      <ul>
        {cartItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

```

#### アイテムをカートに追加するコンポーネントでContextを使う

```jsx

function AddItemButton({ item }) {
  const { addToCart } = useContext(CartContext);

  return <button onClick={() => addToCart(item)}>「{item}」をカートに追加</button>;
}

```

#### 全体をラップする

```jsx

function App() {
  return (
    <CartProvider>
      <AddItemButton item="りんご" />
      <AddItemButton item="オレンジ" />
      <Cart />
    </CartProvider>
  );
}

export default App;

```

##  useContextの注意点

#### 1. 大規模アプリでは複雑化しやすい
- 複数のContextを作成する場合、それぞれのProviderでラップする必要があり、コードが見づらくなることがあります。
- ReduxやZustandなどの状態管理ライブラリを使うことも検討しましょう。

#### 2. 不要な再レンダリングに注意
- Contextに依存するすべてのコンポーネントが、値の変更時に再レンダリングされます。
- 性能が気になる場合は、値を分割するか、React.memo を活用するのが良いです。
#### 3. 依存関係の管理が重要
- Contextの値を変更する処理が複雑になると、管理が難しくなることがあります。

## まとめ

- useContext は React の Context を簡単に使うためのフックで、グローバルなデータ共有に役立つ
- 手順
    1. createContext で Context を作成
    2. Provider を使って値を渡す
    3. 子コンポーネントで useContext を呼び出して値を取得・操作する
- テーマ管理、認証情報、カート機能など、複数のコンポーネントで同じデータを使う場合に便利
- ただし、大規模アプリではReduxなどの状態管理ライブラリを使うことも検討すると良い