React状態管理の最適解:useStateからZustandまで、迷わない選定基準

Reactアプリケーションを開発していると、必ずと言っていいほどぶつかる壁が「状態管理(State Management)」です。 「このデータを複数のコンポーネントで共有したいけど、Propsでバケツリレーするのは避けたい」「どのライブラリを使えばいいのか、選択肢が多すぎて分からない」といった悩みは、初心者から上級者まで共通のトピックです。
この記事では、React標準の機能からモダンな外部ライブラリまで、それぞれの役割とメリット・デメリット、そして「現場で使える選定基準」を2500文字以上の圧倒的ボリュームで解説します。
1. 状態管理の3つのレベル
まず、アプリケーション内の状態(データ)を以下の3つのレベルに分けて考えることが大切です。
① ローカルステート (Local State)
特定の1つのコンポーネント内だけで使われる状態です。
- 例: フォームの入力値、モーダルの開閉フラグ、ローカルなローディング状態。
- 解決策: React標準の
useStateやuseReducerで十分です。
② グローバルステート (Global State)
アプリ全体の多くの場所で共有される状態です。
- 例: ログインユーザー情報、ユーザーの言語設定、ダークモードのテーマ設定。
- 解決策: Context API や外部ライブラリ(Zustand, Reduxなど)。
③ サーバーステート (Server State)
サーバーから取得したデータのキャッシュです。
- 例: APIから取得した記事一覧、ユーザープロフィール。
- 解決策: TanStack Query (React Query) や SWR。
- 重要: これをグローバルステート管理ライブラリ(Reduxなど)で管理しようとすると、実装が非常に複雑になります。サーバーデータは専用のライブラリに任せるのが今のトレンドです。
2. React標準機能による管理
外部ライブラリを導入する前に、まずは標準機能でどこまでできるかを知る必要があります。
useState & useReducer
最も基本的で強力なツールです。状態が複雑になる(複数の関連する値がある)場合は、useReducer を使うと更新ロジックをコンポーネントの外に切り出せて見通しが良くなります。
Context API
「Prop Drilling(Propsのバケツリレー)」を防ぐための解決策です。
- メリット: 外部ライブラリ不要で、React単体でグローバルな値を扱える。
- 注意点: Providerの配下にあるコンポーネントは、管理している値の一部が変わっただけでもすべて再レンダリングされる可能性があります。高い頻度で更新されるデータの管理には向きません。
3. モダンな外部ライブラリの台頭
Context APIの制限を克服し、より使いやすく進化したのが以下のライブラリたちです。
Zustand(ズスタンド):現在の第一候補
現在、Reactコミュニティで最も勢いがあるのが Zustand です。
- 特徴: 非常に軽量で、記述がシンプル。Reduxのような複雑なボイラープレート(定型文)が一切不要。
- メリット:
- Reduxのように「どこからでもアクセスできる店舗」を簡単に作れる。
- 「値が変わったコンポーネントだけ」を再レンダリングさせることができる。
- React以外の環境でも動作する。
Recoil / Jotai(アトム指向)
「状態を小さなアトム(原子)に分割する」という考え方のライブラリです。
- 特徴: コンポーネントツリーとは独立して状態を管理できる。
- メリット: 状態間の依存関係(AとBが計算されてCになる、など)を表現するのが非常に得意です。
4. 失敗しない「選定基準」ガイド
結局どれを使えばいいのか?現場での判断基準は以下の通りです。
- まずは
useStateから始める- できる限り、状態はそれを必要とする最小のコンポーネントに閉じ込めましょう。
- バケツリレーが苦しくなったら
Zustandを検討する- 「認証情報」や「UIの全体設定」など、本当にアプリ全体で共有が必要なものだけを Zustand に移します。Context APIで頑張るよりも、Zustandの方がパフォーマンス管理が楽な場合が多いです。
- サーバーからのデータ取得は
TanStack Query一択- APIのキャッシュ、ローディング、リトライなどは、グローバルステート管理から切り離して管理しましょう。これだけでコードの半分が消え、劇的にシンプルになります。
- Redux は「必要な場合のみ」
- 非常に大規模で、厳格な規約が必要なレガシープロジェクトや特定のルールがある場合を除き、新規で Redux を選ぶ理由は少なくなっています。
5. 状態管理を綺麗に保つためのコツ
ライブラリを使う以前に、設計で気をつけるべきポイントがあります。
- 状態を「派生」させる:
- 「苗字」と「名前」というStateがあるとき、「フルネーム」という別のStateを作る必要はありません。レンダリング中に計算するだけで十分です(不必要なStateは不整合の元です)。
- Stateをリフトアップ(持ち上げ)しすぎない:
- 「とりあえず親に持たせておく」と、アプリ全体が重くなります。本当に必要な高さまでしか持ち上げない勇気を持ちましょう。
まとめ:適材適所で最強の開発体験を
Reactの状態管理は、もはや「Reduxを頑張って覚える」時代から、「最適なツールを組み合わせて楽をする」時代になりました。
- シンプルなUI操作は useState
- アプリ全体の定数や設定は Zustand
- APIデータは TanStack Query
この組み合わせ(スタック)を基本に据えることで、あなたのReact開発はより楽しく、メンテナブル(保守しやすい)なものになるはずです。状態管理の迷路から抜け出し、ユーザー体験を磨くための本質的な実装に集中していきましょう!
次回の記事では、今回少し触れた「Zustand」の具体的な実装例をコードベースで紹介します。