React Context とは?
なぜ Context を使うの?
React Context を使うと、コンポーネントツリーの指定した部分で、共通に使えるデータストアを簡単に実装できます。
ステート (state, 状態) をそのまま使うということも、もちろんできます。しかし、例えば親ノードで定義したステートを孫ノードで変更しようと思ったら、 変更の要求を孫から親の親へと伝えないといけない都合が出てきます。これはなかなか面倒で、仕組みも複雑になり、ややこしく、メンテナンスしにくいコードになりがちです。
そこで、Context を用意します。Context からデータをとって使い、変更が必要ならそこで行うようにします。
Context API で登場するモノと役割
React では Context を使えるようにするための仕組みが、Context API として用意されています。
Context オブジェクトを作るには createContext() 関数を呼びます。
Context には、関連付けされた「プロバイダ (Provider)」と「コンスーマ (Consumer)」があります。
Provider の役割は大きく二つあります。ひとつは、コンテキストの適用範囲をきめることです。そして二つ目はコンテキストにデータを置くことです。
一方、Consumer はコンテキストからデータを取り出して使うために使います。コンスーマでコンテキストからデータ変更用の情報も渡されれば、データの更新をすることもできるようになります。
Context は状態(state)と組み合わせて使うのが一般的です。ところが state は従来、クラスコンポーネントを必要としていました。
コンポーネントの種類は大別して、クラスコンポーネントと関数コンポーネントの二つがあります。
React バージョン 16.8.0 でフック (Hooks) が導入され、state がファンクションコンポーネントでも使えるようになりました。 これによって Context の書き方もだいぶ変わりました。
フックを使わなくても構いませんが、フックを使うことでとてもシンプルになります。
Provider と Consumer の基本的な実装方法
ここでは Context オブジェクトを構成する基本的な要素である、Provider と Consumer の基本的な使い方を紹介します。
実際に開発に利用する時には、これにさらにステート (state) の管理などが加わりもう少し複雑になりますが、 まずはベースとなるところをおさえておきましょう。
具体的には記事「Context API を使う具体例」でサンプルを作ります。ここでは概要だけを説明します。
Provider の基本的な実装
Context オブジェクトの作成と Provider の基本形は次のようになります。
import React, { createContext } from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
const fruits = ['Apple', 'Orange', 'Banana'];
export const FruitContext = createContext();
ReactDOM.render(
<React.StrictMode>
<FruitContext.Provider value={{ fruits }}>
<App />
</FruitContext.Provider>
</React.StrictMode>,
document.getElementById('root')
);
7 行目で useContext() 関数を使って Context オブジェクトを作成しています。あとで Consumer で参照するので export しています。
11 行目と 13 行目で App 要素を取り囲んでいます。これによってコンテキストのスコープが、コンポーネントツリーにおける App 以下になります。
また 11 行目で、 value プロパティに、データソースとなる配列を渡しています。
Consumer の基本的な実装
プロバイダ側でコンテキストにセットしたデータ (ここでは fruits) は、Consumer で受け取ることができます。
import React from 'react';
import './App.css';
import { FruitContext } from './index';
function App() {
return (
<FruitContext.Consumer>
{(value) => {
const { fruits } = value;
console.log(fruits); // ["Apple", "Orange", "Banana"]
return (
<h1>...</h1>
)
}}
</FruitContext.Consumer>
);
}
export default App;
7 行目から 15 行目で Consumer を使っています。
8 行目のアロー関数のパラメータとして、Provider 側で value プロパティに渡したオブジェクトが渡されます。9 行目で分割代入を使って、value から fruits を取り出しています。
useContext フックを使った Consumer の基本的な実装
さらに useContext フックを使うと、Consumer がシンプルにかけます。
import React, { useContext } from 'react';
import './App.css';
import { FruitContext } from './index';
function App() {
const { fruits } = useContext(FruitContext);
console.log(fruits); // ["Apple", "Orange", "Banana"]
return (
<h1>...</h1>
);
}
export default App;
FruitContext.Consumer 要素を作成しなくても、useContext フックを使うことで、Consumer に渡される value が直ちに取得できます。