React Contextを用いてデータを楽に扱う

#Contextとは
Reactにはローカルでデータを一時的に保管できる場所として、**state**と呼ばれるものがあるかと思います。しかしプロジェクトが大きくなったり、小さいプロジェクトでも複数のコンポーネントで同じデータ(state)を扱いたいとき、stateを**props**を用いて各コンポーネントに配送する作業をせねばなりません。このデータの配送作業の面倒な部分は、データを**使わないコンポーネント**にも場合によっては中継する必要があり、コード量が増えてしまうことになります。（自分を困惑させるようなコードが増えます）
ここで登場してのが**ContextAPI**と呼ばれるものです。このCotextAPIというものを用いれば従来のstateではなく、**context**というデータ保管庫を全てのコンポーネントの中央に置くことができます。このcontextはイメージとしてはハブ空港のようなもので、あるデータを使いたいコンポーネントは**親コンポーネント**を経由することなくcontext(データ保管庫)から直接データを受け取れます。使ったことある方も多いと思いますが、**Redux**と考え方、動きは非常に似ています。

#ContextとProviderを作成する
まずはsrcディレクトリの直下に**context**を作成するファイルを入れるcontextフォルダを作ります。（ディレクトリを作成する必要はありませんが、分かりやすくするためです。）その中に実際にcontextを作るファイルを作成します。今回は画面の配色データを保管するcontextを作成するため、ファイル名は**ThemeContext.js**としました。
下のコードにある通り、まずはcreateContext関数を用いてcontextを作成します。ただこれだけではデータを保管する部分、コンポーネントにデータを届ける（**provide**）機能は設定しておらず。何も動きません。実際にデータを保管する場所、データを配送する機能は**Provider**と呼ばれるコンポーネントを作成し、その中で設定します。最初に自分の使いたいデータの保管部分を作成しましょう。少し驚くかと思いますがデータを保管するのは**state**です。stateオブジェクトに自分の使いたいデータを入れましょう。

```react:ThemeContext.js
import React, { createContext } from 'react';
// createContextはcontextを作成してくれる関数

export const ThemeContext = createContext();
// contextを作成し、外部でも使えるようエクスポートしておく


class ThemeContextProvider extends React.Component {
    state = {
        isLightTheme: true,
        light: {
            syntax: '#555',
            ui: '#ddd',
            bg: '#eee'
        },
        dark: {
            syntax: '#ddd',
            ui: '#333',
            bg: '#555'
        }
    }

    render() {
        return (
            // 動的な値であるため{}で囲み、stateのコピーを入れるために{}を書く
            // 従って2重の{}が必要となる。
            <ThemeContext.Provider value={{...this.state}}>
                {this.props.children}
            </ThemeContext.Provider>
        );
    }
}

export default ThemeContextProvider;
```

次にProviderを作成します。Providerとは簡単に言えば**タグ**です。contextはデータを各コンポーネントに送る際に、そのコンポーネントを**タグ(Provider)**で囲むことで、コンポーネントに対してデータを送り、操作できる機能も与えます。タグというだけあって**render関数**の中のJSXとして記述します。上のコードのように**ThemeContext.Provider**と書きます。createContext関数を用いて作られたcontextには**Provider**が付与されるためです。このProviderがコンポーネントを囲むことでデータを送ることができ、コンポーネントはデータを扱うことができます。Providerには**valueプロパティ**を設定しなければなりません。valueプロパティの値には送りたいデータを記述します。従ってスプレッド構文を用いてstateの中身をコピーし、値とします。これによりProviderによって囲まれたコンポーネントはvalueプロパティ内のデータをを使うことができます。ただProvider側は囲まれたコンポーネントをどのようにして認識するのか。それが**{ this.props.children }**の部分です。
では上コードの**{ this.props.children }**とは何か。**this.props.children**は子コンポーネントを表します。下のコードのようにコンポーネント達がcontextを使いたい場合、App.jsでProviderに囲んでもらいます。囲まれたコンポーネントはProvider側から見れば子コンポーネントとなり、このように書くことで、Providerは囲まれたコンポーネント全てを認識できます。

```react:App.js
import React from 'react';
import Navbar from './components/Navbar';
import Todo from './components/Todo';
import ThemeContextProvider from './context/ThemeContext';

function App() {

  return (
    <div className="App">
      <ThemeContextProvider>
        <Navbar />
        <Todo />
      </ThemeContextProvider>
    </div>
  );
}

export default App;

```

#Contextのデータを使ってみる（クラスベース）
Providerによりコンポーネントを囲んだら、そのコンポーネントに移動し、まずcontextをインポートします。あとは下のコードにある通り**contextType**に自分の使いたいcontextを代入すれば、**this.context**でコンポーネントからcontextにアクセスできるようになります。

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

class Navabar extends Component {
    // これによりthis.contextで、contextにアクセスできる
    static contextType = ThemeContext;
    render() {
        console.log(this.context);
        return (
            <nav>
                <h1>Context App</h1>
                <ul>
                    <li>Home</li>
                    <li>About</li>
                    <li>Contact</li>
                </ul>
            </nav>
        )
    }
}

export default Navabar;
```

#最後に
読んでくれた方はありがとうございます。間違い、誤字などございましたら、お気軽に指摘していただけると助かります。