🙌

React Context APIはStoreの代替になるか

2021/04/23に公開

執筆の動機

直近1年の間、アーキテクチャを決めている際に表題の質問を2つの現場で受け、気になっている人が多いのかと思い、まとめてみようと思います。

結論

結論から書いていくと、代替にはなりません
両者の特性を踏まえた上で、両方を共存させた上で使い分けるか、アプリケーションの規模に応じて、どちらかを選択しましょう。

Context APIの特徴

そもそもこの議論(特にReduxを指して)が起こったきっかけは、React 16.3でContext APIが大幅に変更され、公開されたことです。
なぜ、新しいContext APIがReduxの代替になり得ると思われたのか、ざっくりContext APIを見ていきます。

概要

Reactコンポーネントの特定のツリーに対して、グローバルなデータを提供し、その子孫コンポーネントは階層も関係なしにグローバルなデータにアクセスできるようになります。

// コンテクストを使用すると、全てのコンポーネントを明示的に通すことなしに
// コンポーネントツリーの深くまで値を渡すことができます。
// 現在のテーマ(デフォルトは "light")の為のコンテクストを作成します。
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // 以下のツリーへ現在のテーマを渡すためにプロバイダを使用します。
    // どんな深さでも、どのようなコンポーネントでも読み取ることができます。
    // このサンプルでは、"dark" を現在の値として渡しています。
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 中間のコンポーネントはもう明示的にテーマを
// 下に渡す必要はありません。
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 現在のテーマのコンテクストを読むために、contextType に指定します。
  // React は上位の最も近いテーマプロバイダを見つけ、その値を使用します。
  // この例では、現在のテーマは "dark" です。
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

※Reactの公式ドキュメントより引用

関心

Context APIの関心は、prop drillingを解消することです。
Reduxの関心も似ていたため、代替になるのではないかと思われたのだと思います。

開発における違い

では、ReduxとContext APIの間にはどのような違いがあるのでしょうか?
もちろんこれだけではないのですが、テーブルにまとめてみました。

Redux Context API
スコープ アプリケーション全体 子孫component間
管理対象 アプリケーション全体の状態 変更頻度の低いデータ
ミドルウェア
開発者ツール

Context APIはアプリケーション全体の状態を管理するようには設計されておらず、下記のようにReact Componentの木構造においてグローバルなデータを共有するように設計されています。

Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.

また、認証情報やテーマなどが対象として例示されているように、(変更頻度の多い)状態をContext APIで扱うようには設計されていないように思えます。
公式ドキュメントでも言及されているように、Context APIは不要な再描画を引き起こしやすく、状態を取り扱う場合、その制御が開発コストに上乗せされます。

それぞれが適しているケース

上記のような違いを踏まえた上で、それぞれが適しているケースをまとめてみました。

Redux Context API 判断理由
アプリケーションの規模 スコープの違い
データの更新頻度 設計思想と再描画の制御
非同期処理 ミドルウェアの有無

両者は設計思想や目的がそもそも異なるため、ケースバイケースで使い分けられるべきものです。
よって、Context APIはStoreの代替にはなりません。

Discussion