React Context APIはStoreの代替になるか
執筆の動機
直近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