概要


今回の記事では、Reactコンポーネント間のデータやりとりにおける冗長性を低減できるテクニックであるContextについて記します。有効活用できていない人は本記事を読んで是非活用してみてください。


React Contextとは


context 【意味】文脈、環境

Reactでは、画面に表示する目的のパーツをコンポーネントベースで構成して全体を構築していくという方針でコードを書いていくかと思います。一般に、1ファイルにつき1コンポーネントを書くことが暗黙の了解とされていることから、コンポーネント間でのデータのやりとりは必須です。コンポーネント間でデータをやりとりする方法としてはpropsを介して行いますが、コンポーネントツリーが複雑になるような場合や、離れたコンポーネント間でデータをやりとりする場合などを考えると、propsによる冗長なバケツリレーによって、コーディングが複雑になるだけでなく可読性も低くなるといった問題が生じ得ます。

ここで「コンポーネントを空港、データを飛行機と見立てたようなモデル」を考えてみましょう。仲介する地点が不要になるこのモデルでは、データは出発地から目的地まで一発で辿り着くことができ、最も簡潔化されたモデルのように思えます。Contextはこのモデルを可能にする、「コンポーネントに動的に値を渡すReact純正のAPI」です。


React Contextの仕組み


React Contextでは、大きく「データをContext化するProviderコンポーネント」と「Contextデータを回収するuseContextフック」の使い方が重要です。

まず初めにContextに関わる2つのReactの機能について紹介します。


1. React.createContext

新しいContext objectを生成することができる関数です。

import { createContext } from 'react';

const SampleComponent = createContext();

// SampleComponentにProvider/Consumerコンポーネントが与えられる

ここでSampleComponentに与えられるコンポーネントはそれぞれ次のような役割を持ちます。

○Providerコンポーネント

 propertyにContext化したいデータを書くことで、wrapするコンポーネント全体にそのContextデータを渡すことができるコンポーネントです。

○Consumerコンポーネント

 Providerコンポーネントにwrapされているコンポーネントにデータを渡すことができるコンポーネントです。ですが、次に紹介するuseContextフックの登場によりConsumerコンポーネントについては直接コーディングせず目的のデータ取得が可能になりました。


2. React.useContext

Contextからデータを取得する際に使われるフックです。上で説明したConsumerコンポーネントにアクセスしてcontextに置いてあるデータを取得するのに使われます。


データをContextに置く


今回の記事では、ある組織のメンバーリストを表示させるという例を使います。jsonファイルからimportしたメンバーリスト(memberList)をContextに置きたいデータとします。

import React, { createContext } from "react";
import memberList from "./member-data";
import { render } from "react-dom";
import App from "./App";

export const MemberContext = createContext();

render(
    <MemberContext.Provider value={{ memberList }}>
        <App />
    </MemberContext.Provider>,
    document.getElementById("root")
);

このように書くことで、memberListデータをProviderコンポーネント配下のAppコンポーネントにContextデータとして渡すことができます。


Contextからデータを取得する


MemberContextに置いたmemberListデータは、データを取得したいコンポーネントで次のように書くことによって取得することができます。

import React, { useContext } from "react";
import { MemberContext } from "./";
import Member from "./Member";

export default function MemberList() {
    const { memberList } = useContext(MemberContext);
    if (!memberList.length) return <div>No Members Listed. (Add a Member</div>;
    return (
        <div className="member-list">
            {
                memberList.map(member => <Member key={member.id} {...member} />)
            }
        </div>
    );
}

まとめ


以上、Contextの概念とその基本的な使い方についてまとめてきました。Contextはコンポーネント間のデータのやりとりをより簡潔にするコーディングですので、是非参考にしてみてください。