基礎から学ぶReact/React Hooks学習メモ 5-5 useContext

# React Hooksを基礎から理解する 5-5 useContext

参考
[基礎から学ぶReact/React Hooks](https://www.amazon.co.jp/dp/B09CP8T4TX)

## useContextとは

- コンポーネントのさまざまな階層からContextに収容されているデータへのアクセスをすることができる。
- 親から子、孫へ、propsのいわゆるバケツリレーをしなくても直接値を渡せる。
- Contextオブジェクト
    - React.createContext()の戻り値

```js
const SampleContextObject = React.createContext();
```

- Providerコンポーネント
    - Contextオブジェクトが保持しているコンポーネント
    - 1つのContextで管理できる「コンテキストオブジェクトの値」は1つだけ。
    - ConsumerComponentコンポーネントはProvider内なので、value属性の値を参照できる。

```js
<SampleContextObject.Provider value={ツリー内で共有可能なコンテキストオブジェクトの値} >

  <ConsumerComponent />

</SampleContextObject.Provider>
```

- Consumerコンポーネント
    - useContext()を利用することで、Contextから値を取得できるコンポーネント


```js
import React, { useContext } from "react";


const コンテキストオブジェクトの値 = useContext(コンテキストオブジェクト);
```

## useContextの利用例

- Providerコンポーネントで共有されたデータをConsumerコンポーネントで受け取る

```js
import React, { createContext, useContext } from "react";
import "./styles.css";

// contextオブジェクトの生成
const SampleContextObject = createContext();

const ConsumerComponent = () => {
  // 親コンポーネントからmessageTextを取得
  const messageText = useContext(SampleContextObject);
  console.log(messageText);
  return <p>{messageText}</p>;
};

const message = "I love React!!";

export default function App() {
  // 親コンポーネントに文字列を設定して、Providerでラップする
  return (
    <SampleContextObject.Provider value={message}>
      <ConsumerComponent />
    </SampleContextObject.Provider>
  );
}
```

## Providerコンポーネントからテキストデータを渡してみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88686/f602f932-2729-2224-8297-263ee65008e7.png)


```js:TextProvider.js
import React, { createContext } from "react";

export const TextContext = createContext();

const text = "これはProviderから渡されたテキストです。";

export const TextProvider = ({ children }) => {
  return <TextContext.Provider value={text}>{children}</TextContext.Provider>;
};
```

```js:App.js
import { TextProvider } from "./TextProvider";
import { First } from "./First";
import "./styles.css";

export default function App() {
  return (
    <div>
      <TextProvider>
        <First />
      </TextProvider>
    </div>
  );
}
```

```js:First.js
import { Second } from "./Second";

export const First = () => {
  return (
    <>
      <p>Firstコンポーネント</p>
      <Second />
    </>
  );
};
```

```js:Second.js
import { Third } from "./Third";

export const Second = () => {
  return (
    <>
      <p>Secondコンポーネント</p>
      <Third />
    </>
  );
};
```

```js:Third.js
import React, { useContext } from "react";
import { TextContext } from "./TextProvider";

export const Third = () => {
  const textData = useContext(TextContext);

  return (
    <>
      <p>
        Thirdコンポーネント: <b>{textData}</b>
      </p>
    </>
  );
};
```

## useStateを利用したcountデータを渡す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88686/4fa226e7-50f4-090c-a232-a76bb8a338c6.png)

- [count, setCount]をProviderのvalueに渡すと、受け取ったコンポーネントから値を変更できる

```js:TextProvider.js
import React, { createContext, useState } from "react";

export const TextContext = createContext();

// const text = "これはProviderから渡されたテキストです。";

export const TextProvider = ({ children }) => {
  const [count, setCount] = useState(0);

  return (
    <TextContext.Provider value={[count, setCount]}>
      {children}
    </TextContext.Provider>
  );
};

```

- App.jsは上のApp.jsと同じ
- First.jsは上のFirst.jsと同じ
- Second.jsは上のSecond.jsと同じ
- `[count, setCount]`を受け取り、値を参照・変更できる

```js:Third.js
import React, { useContext } from "react";
import { TextContext } from "./TextProvider";

export const Third = () => {
  // const textData = useContext(TextContext);
  const [count, setCount] = useContext(TextContext);

  const handleClick = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <>
      <p>
        Thirdコンポーネント: <b>現在のカウント: {count}</b>
      </p>
      <button onClick={handleClick}>＋１ボタン</button>
    </>
  );
};
```