React.contextとは？

<h2>contextとは</h2>
コンポーネントツリーを越えてデータを共有する方法です。
子コンポーネントの深さが深まると、引き続けてState管理のためにpropsを渡さなければならない状況になってしまいます。 そのようなことを解決するためにcontext apiを提供します。
contextを利用すれば、コンポーネントツリー全体にデータを提供することができます。（props drillingを防ぐ）
グローバルなデータを共有する必要があるときに使用！

<h2>contextの流れ</h2>
1. create Contextメソッドを使ってcontextを生成する。<br>
2. 生成されたcontextを持ってcontext providerでコンポーネントツリーを包む。<br>
3. value propを使ってcontext providerに希望する値を入力する。<br>
4. context consumerにて必要なコンポーネントからその値を読み込む。

<h2>contextの例</h2>

```react:ThemeContext.js
import React from 'react'

export const themes = {
    light: {
        foreground: '#000000',
        background: '#eeeeee',
    },
    dark: {
        foreground: '#ffffff',
        background: '#222222',
    },
}

export const ThemeContext = React.createContext(themes.dark);
```
React.createContext()を使って、共有したいデータを定義します。
これはthemes.darkをdefaultValueとして使うと言う定義になります。
defaultValueとはあるコンポーネントがProviderを探せない（親子関係❌）時に使う値です。

```react:ThemedButton.jsx
import React, { Component } from 'react'
import { ThemeContext } from './ThemeContext';

class ThemedButton extends Component {
  render() {
      let props = this.props;
      let theme = this.context;
    return (
      <button 
        {...props} 
        onClick={props.changeTheme}
        style={{ backgroundColor: theme.background, color: theme.foreground }}>
            button1
      </button>
    );
  }
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
```
React.createContext()で生成したContextオブジェクト（ThemeContext）を
希望するクラスのcontextTypeプロパティに指定できます。 
このプロパティを活用して、クラス内でthis.contextを利用して該当Contextの最も近いProviderを探してその値を読むことができるようになります。

```react:Example.jsx
import React, { Component } from 'react'
import { ThemeContext, themes } from './ThemeContext';
import ThemedButton from './ThemedButton';

export default class Example extends Component {
    constructor(props) {
        super(props);
        this.state = {
            theme: themes.light,
        };
        this.toggleTheme = () => {
            this.setState((prev) => ({
                theme: prev.theme === themes.dark ? themes.light : themes.dark,
            }));
         };
    }
  render() {
    return (
      <div>
          <ThemeContext.Provider value={this.state.theme}>
              <ThemedButton changeTheme={this.toggleTheme} />
              <ThemeContext.Consumer>
                  {(theme) => (
                        <div 
                            style={{
                                height: 300, 
                                    width:300, 
                                    backgroundColor: theme.background,}}
                                    ></div>
                                )}
              </ThemeContext.Consumer>
          </ThemeContext.Provider>
          <ThemedButton />
      </div>
    );
  }
}
```
`<ThemeContext.Provider value={this.state.theme}>`で囲まれている
`<ThemedButton>`のbackgroundColorはProvider value propsにより、backgroundColorは”light”になります。Providerはvalue propを受けてこの値を下位にあるコンポーネントに転送するためです。下位のThemedButtonをクリックすると、toggleThemeによって、backgroudColorが変わります。<br>
`<Context.Consumer>`のthemeパラメータは、該当contextのProviderの中で上位ツリーから最も近いProviderのvaluepropと同じです。なので、`<ThemedButton>`と`<Context.Consumer>`のbackgroundColorは共有され、いつも同じです。
一番下の`<ThemedButton />`は`<ThemeContext.Provider>`に囲まれていなため、
ThemeContext.jsの以下のロジックにより、いつもbackgroundColorはdarkです。
export const ThemeContext = React.createContext(themes.dark);

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/d0775c3f-1b44-f108-4c39-40de9f354fb6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/ee6c4150-0b21-2f21-d5fd-7115ddd6364c.png)

<h2>useContext Hook</h2>
useContextとは、contextオブジェクト(React.createContextで返還された値)を受け、そのcontextの現在の値を返還します。
class componentでは、this.contextの形でThemeContextの値を受けましたが、
function componentでは、useContextを使って、以下のように使うことが可能です。

```react:ThemedButton.jsx
import React from 'react'
import { useContext } from 'react'
import { ThemeContext } from './ThemeContext'

export default function ThemedButton(props) {
    const theme = useContext(ThemeContext)
  return (
          <button 
        {...props} 
        onClick={props.changeTheme}
        style={{ backgroundColor: theme.background, color: theme.foreground }}>
            button1
            </button>
  )
}
```