ReactのContext APIとReduxの違いを初心者向けに徹底比較!どちらを使うべきか完全解説
生徒
「状態管理を調べたらContext APIとReduxの両方が出てきたんですが、どっちを使えばいいんですか?」
先生
「どちらもReactでグローバルな状態を管理するための仕組みですが、向いている場面が違います。まず両者の特徴を理解することが大切です。」
生徒
「Reduxはよく名前を聞くんですが、難しそうで怖いです。Context APIだけじゃダメなんですか?」
先生
「アプリの規模や用途によって選び方が変わります。それぞれの特徴をコードと一緒に見ていきましょう!」
1. Context APIとReduxはどちらも「グローバルな状態管理」の仕組み
ReactでWebアプリを作るとき、複数のコンポーネントをまたいで共有したいデータのことをグローバルステート(グローバルな状態)といいます。ログイン中のユーザー情報、テーマ設定、カートの中身などがその代表例です。
このグローバルステートを管理するための仕組みがContext APIとReduxです。どちらも「アプリ全体でデータを共有する」という目的は同じですが、設計思想や使い方が異なります。
Context APIはReactに標準で組み込まれている機能です。追加のライブラリをインストールする必要がなく、createContextとuseContextを使うだけでグローバルな状態管理が実現できます。
Reduxは外部ライブラリです。インストールが必要ですが、大規模なアプリでも状態の変化を予測しやすく管理できる設計になっています。現在はRedux Toolkitという書きやすくした公式パッケージが主流です。どちらが優れているというものではなく、アプリの規模や目的に合わせて使い分けることが大切です。
2. Context APIの書き方をおさらいしよう
まずContext APIの基本的な書き方を確認しておきましょう。createContextでContextを作り、Providerでデータを提供し、useContextで取り出すという3ステップが基本です。
import React, { createContext, useContext, useState } from "react";
// Contextを作成する
const CountContext = createContext(null);
function CountProvider({ children }) {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
}
function Counter() {
const { count, setCount } = useContext(CountContext);
return (
<div>
<p>カウント:{count}</p>
<button onClick={() => setCount(count + 1)}>増やす</button>
<button onClick={() => setCount(count - 1)}>減らす</button>
</div>
);
}
function App() {
return (
<CountProvider>
<Counter />
</CountProvider>
);
}
export default App;
Context APIはこのようにシンプルな書き方で状態管理ができます。追加パッケージなし、設定ファイルなし、覚えるルールも少ないため、Reactを学び始めたばかりの方でも取り組みやすいのが特徴です。
3. Reduxの基本的な考え方と仕組みを理解しよう
Reduxには独自の設計ルールがあります。主要な概念としてStore(ストア)、Action(アクション)、Reducer(リデューサー)の3つがあります。
Storeとは、アプリ全体の状態をひとつにまとめて保管する場所です。データの倉庫のようなイメージです。Actionとは、「どんな操作をしたいか」を表すオブジェクトです。{ type: "INCREMENT" }のように操作の種類を指定します。Reducerとは、Actionを受け取って、現在の状態をどのように変化させるかを決めるルール集です。
Reduxでは「状態はStoreで一元管理し、Reducerというルールを通してのみ変更できる」という厳密な決まりがあります。この一方向のデータの流れが、アプリが大きくなっても状態の変化を追いやすくしている理由です。
現在はRedux Toolkitという公式パッケージを使うのが標準的です。Redux Toolkitを使うと、以前のReduxに比べてコードの記述量が大幅に少なくなります。
4. Redux Toolkitを使った基本的なコードを見てみよう
Redux Toolkitを使ったカウンターの例を見てみましょう。Context APIの例と同じ動きをするコードです。まずnpmでインストールが必要です。
// インストール: npm install @reduxjs/toolkit react-redux
import React from "react";
import { configureStore, createSlice } from "@reduxjs/toolkit";
import { Provider, useSelector, useDispatch } from "react-redux";
// Sliceを作成(状態と操作をまとめたもの)
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
},
});
const { increment, decrement } = counterSlice.actions;
// Storeを作成する
const store = configureStore({
reducer: { counter: counterSlice.reducer },
});
function Counter() {
// useSelectorでStoreからデータを取得する
const count = useSelector((state) => state.counter.value);
// useDispatchで操作を送り出す関数を取得する
const dispatch = useDispatch();
return (
<div>
<p>カウント:{count}</p>
<button onClick={() => dispatch(increment())}>増やす</button>
<button onClick={() => dispatch(decrement())}>減らす</button>
</div>
);
}
function App() {
return (
// ProviderでStoreをアプリ全体に提供する
<Provider store={store}>
<Counter />
</Provider>
);
}
export default App;
Context APIに比べてコードの量が増え、覚えるべき概念も多いことがわかります。一方でSliceという単位でデータと操作がまとまっているため、大きなアプリでもどこに何が書いてあるか整理しやすいという利点があります。
5. Context APIとReduxの主な違いを表で比べてみよう
Context APIとReduxの違いをわかりやすく整理します。どちらを選ぶかの判断材料になる項目を見ていきましょう。
| 比較項目 | Context API | Redux(Redux Toolkit) |
|---|---|---|
| 追加インストール | 不要(React標準) | 必要(npm install) |
| 学習コスト | 低い | やや高い |
| コード量 | 少ない | 多め |
| 向いているアプリ規模 | 小〜中規模 | 中〜大規模 |
| デバッグのしやすさ | 普通 | Redux DevToolsで強力なデバッグが可能 |
| パフォーマンス最適化 | 自分で工夫が必要 | 組み込みの最適化あり |
デバッグとは、プログラムの誤りを見つけて修正する作業のことです。ReduxにはRedux DevToolsというブラウザの拡張機能があり、状態がどのように変化したか時系列で確認したり、過去の状態に戻したりすることができます。大規模なアプリでの問題調査に非常に役立ちます。
6. Context APIが向いている場面とReduxが向いている場面
Context APIとReduxはそれぞれ得意な場面があります。プロジェクトの特性に合わせて選ぶことが大切です。
Context APIが向いている場面としては、個人開発や学習用の小〜中規模のアプリ、テーマ設定・言語設定・ログイン情報のような更新頻度が低くシンプルなデータの管理、Reactを学び始めた段階でまず状態管理の基本を理解したいとき、外部ライブラリをできるだけ使わずシンプルな構成を保ちたいときなどが挙げられます。
Reduxが向いている場面としては、複数人が関わるチーム開発、状態の変化が複雑で多岐にわたる大規模なアプリ、過去の状態に戻す機能(アンドゥ・リドゥ)が必要なとき、Redux DevToolsを使った高度なデバッグが必要なとき、非同期処理(APIからのデータ取得など)を一元管理したいときが代表的です。
「とりあえずどちらかを選ぶ」のであれば、まずContext APIで十分なことが多いです。アプリが成長してContext APIでは手に負えなくなってきたタイミングでReduxへの移行を検討するのが、無駄のない進め方といえます。
7. Context APIとReduxを組み合わせて使うことはできるのか
Context APIとReduxは、排他的な関係ではなく同じアプリの中で共存させることもできます。たとえばアプリ全体で使うログイン情報はContext APIで管理し、複雑な商品検索や注文処理の状態管理にはReduxを使う、というような使い分けが実際の開発でも見られます。
ただし、ひとつのアプリで複数の状態管理の仕組みを混在させると、新しくプロジェクトに参加した開発者が混乱しやすくなるデメリットもあります。どの状態をどこで管理しているかのルールを明確にしておくことが重要です。
初心者のうちは、Context APIとReduxのどちらかに絞って習得することをおすすめします。Context APIを使いこなせるようになると、ReduxやZustandといった他のライブラリを学ぶときにも「状態管理とは何か」という概念の理解が土台になるため、習得がスムーズになります。
8. 非同期処理との組み合わせ:Context APIとReduxのアプローチの違い
実際のアプリでは、サーバーからデータを取得する非同期処理を扱う場面が多くあります。非同期処理とは、時間のかかる処理(たとえばサーバーへのリクエスト)を待っている間も、他の処理を続けられる仕組みのことです。
Context APIで非同期処理を扱うときは、useEffectと組み合わせてデータ取得を行い、その結果をuseStateで管理してContextに渡す方法が一般的です。
import React, { createContext, useContext, useState, useEffect } from "react";
const DataContext = createContext(null);
function DataProvider({ children }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 擬似的なAPI通信(実際はfetchなどを使う)
setTimeout(() => {
setData({ message: "サーバーからのデータです" });
setLoading(false);
}, 1500);
}, []);
return (
<DataContext.Provider value={{ data, loading }}>
{children}
</DataContext.Provider>
);
}
function DataDisplay() {
const { data, loading } = useContext(DataContext);
if (loading) return <p>読み込み中...</p>;
return <p><i class="bi bi-check-circle-fill text-success"></i> {data.message}</p>;
}
function App() {
return (
<DataProvider>
<DataDisplay />
</DataProvider>
);
}
export default App;
一方ReduxではRedux ToolkitのcreateAsyncThunkという機能を使うことで、非同期処理のローディング中・成功・失敗の状態を自動的に管理できます。複数のAPIを呼び出すような複雑な非同期処理が多いアプリでは、この仕組みが大きな助けになります。Context APIでも非同期処理は扱えますが、複雑になるほど自分でロジックを書く量が増えます。非同期処理の多さもContext APIとReduxを選ぶ際の判断材料のひとつです。