1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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オブジェクトに自分の使いたいデータを入れましょう。

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は囲まれたコンポーネント全てを認識できます。

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にアクセスできるようになります。

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;

最後に

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

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?