[React] グローバルなstate管理(useContext)

React初心者がグローバルなstate管理について勉強した時のメモです。

## 現状
以下のような階層構造の時に、
App → ComponentA → ComponentB → ComponentC

ComponentCに`あさひ`というUser名の値を渡したい場合、各Componentでpropsのバケツリレーをしないといけない。

```App.jsx
import { ComponentA } from "./components/ComponentA";

export const App = () => {
  const name = "あさひ";
  return (
    <>
      <ComponentA name={name} />
    </>
  );
};

```

```react:ComponentA
import { ComponentB } from "./ComponentB";

export const ComponentA = (props) => {
  const { name } = props;
  return (
    <>
      <p>ComponentA</p>
      <ComponentB name={name} />
    </>
  );
};
```

```react:ComponentB.jsx
import { ComponentC } from "./ComponentC";

export const ComponentB = (props) => {
  const { name } = props;
  return (
    <>
      <p>ComponentB</p>
      <ComponentC name={name} />
    </>
  );
};
```

```react:ComponentC.jsx
export const ComponentC = (props) => {
  const { name } = props;
  return (
    <>
      <p>ComponentC</p>
      <p>{name}</p>
    </>
  );
};
```
## Contextを使ったstate管理
### Providerの作成

Providerを作成します。

```react:UserProvider.jsx
import React, { createContext } from "react";

export const UserContext = createContext({})

export const UserProvider = (props) => {
  const { children } = props;
  const contextName = "あさひ"

  return (
    <UserContext.Provider value={{ contextName }}>
      {children}
    </UserContext.Provider>
  )
}
```
ここで今回受け渡したい値のUser名`あさひ`を設定します。
`createContext`を使用し以下のように囲うことで`{children}`に入ってくるコンポーネントではどこでもvalueの値を参照することができます。

```react
<UserContext.Provider value={{ contextName }}>
  {children}
</UserContext.Provider>
```

```react:App.jsx
import { ComponentA } from "./components/ComponentA";
import { UserProvider } from "./provider/UserProvider";

export const App = () => {
  
  return (
    <UserProvider>
      <ComponentA/>
    </UserProvider>
  );
};
```
作ったProviderコンポーネントをApp.jsxでComponentAを囲います。
これでComponentA以下の全てのComponentでProviderで設定した値の参照ができます。

### useContext
`useContext`を使用してComponentCで値を取得します。
今回は`UserContext`の`contextName`を取得しています。

```react:ComponentC.jsx
import { useContext } from "react";
import { UserContext } from "../provider/UserProvider";

export const ComponentC = () => {
  const name = useContext(UserContext);
  return (
    <>
      <p>ComponentC</p>
      <p>{name.contextName}</p>
    </>
  );
};
```

### useStateと使う場合
useStateと一緒に使うことでstateを渡すことができます。
ProviderでuseStateを定義し、valueに値を設定します。
今回はカウントアップのためのstateをComponentCに渡していきます。

```react:UserProvider.jsx
import React, { createContext, useState } from "react";

export const UserContext = createContext({});

export const UserProvider = (props) => {
  const { children } = props;
  const [count, setCount] = useState(0);
  return (
    <UserContext.Provider value={{ count, setCount }}>
      {children}
    </UserContext.Provider>
  );
};
```

```react:ComponentC
import { useContext } from "react";
import { UserContext } from "../provider/UserProvider";

export const ComponentC = () => {
  const { count, setCount } = useContext(UserContext);
  return (
    <>
      <p>ComponentC</p>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>ボタン</button>
    </>
  );
};
```
useContextでProviderでセットしたstateを受け取ることで使用できます。
めっちゃ便利！！