Use Jotai for Global State Management
コンテキスト
Section titled “コンテキスト”3層状態管理アーキテクチャの採用により、Global Stateの管理に特化したライブラリの選定が必要となった。Reduxの非推奨化を受け、より現代的でReactのパラダイムに適合した状態管理ライブラリが求められている。
Global Stateとして管理すべき状態は以下のとおりである。
- ユーザー認証情報とセッション
- アプリケーション全体の設定(テーマ、言語設定など)
- 複数のコンポーネント間で共有される一時的なUI状態
- クライアントサイドのみで管理されるデータ
これらの状態を効率的に管理し、不要な再レンダリングを避けながら、開発者体験を向上させるライブラリが必要である。
Global State管理ライブラリとしてJotaiを採用する。Atomic状態管理のアプローチにより、必要な部分のみの更新と購読を実現し、パフォーマンスと開発効率を両立する。
選択肢1: Jotai(採用案)
Section titled “選択肢1: Jotai(採用案)”-
利点:
- Atomic状態管理により、きめ細かい更新制御が可能
- React Suspenseとの統合が標準でサポート
- TypeScriptファーストな設計で型安全性が高い
- ボイラープレートコードが少ない
- Provider地獄を回避できる(Providerなしでも動作可能)
- React DevToolsとの統合
- 非同期状態の扱いが直感的
- React Server Componentsとの互換性を考慮した設計
-
欠点:
- 比較的新しいライブラリのため、長期的な安定性が未知数
- Redux比で事例やベストプラクティスが少ない
- Atomic概念の理解に学習コストがかかる場合がある
選択肢2: Zustand
Section titled “選択肢2: Zustand”-
利点:
- シンプルなAPI設計
- Redux DevToolsサポート
- 軽量(2KB)
- Reactに依存しない設計
-
欠点:
- Atomicな状態管理ではないため、部分的な更新が難しい
- TypeScriptの型推論がJotaiより弱い
- React Suspenseとの統合が限定的
選択肢3: Valtio
Section titled “選択肢3: Valtio”-
利点:
- Proxyベースで直感的な状態更新
- 自動的な再レンダリング最適化
- シンプルなAPI
-
欠点:
- Proxyの挙動が予測しづらい場合がある
- デバッグが困難な場合がある
- コミュニティが小さい
選択肢4: Redux Toolkit
Section titled “選択肢4: Redux Toolkit”-
利点:
- 成熟したエコシステム
- 豊富なドキュメントと事例
- 強力なDevTools
- 予測可能な状態更新
-
欠点:
- ボイラープレートコードが依然として多い
- Atomic状態管理ではない
- React専用ではないため、React固有の最適化が弱い
- バンドルサイズが大きい
この決定による影響を記述する。
-
ポジティブな影響:
- Atomic状態管理により、パフォーマンスの最適化が容易になる
- コンポーネント単位での状態購読により、不要な再レンダリングを削減
- TypeScriptによる型安全な開発が可能
- React Suspenseを活用した非同期処理の簡潔な実装
- 開発者体験の向上(少ないコード量、直感的なAPI)
-
ネガティブな影響:
- 新しいパラダイムの学習が必要
- 既存のReduxコードからの移行作業が発生
- チーム全体でのAtomic状態管理の理解が必要
-
リスク:
- ライブラリの将来的なメンテナンスの継続性
- 大規模アプリケーションでの実績が相対的に少ない
- Atomの設計を誤ると、管理が複雑化する可能性
実装ガイドライン
Section titled “実装ガイドライン”基本的なAtomの定義
Section titled “基本的なAtomの定義”import { atom } from 'jotai'
// プリミティブなatomexport const themeAtom = atom<'light' | 'dark'>('light')
// 派生atomexport const isDarkModeAtom = atom( (get) => get(themeAtom) === 'dark')
// 非同期atomexport const userAtom = atom(async () => { const response = await fetch('/api/user') return response.json()})コンポーネントでの使用
Section titled “コンポーネントでの使用”import { useAtom } from 'jotai'
function ThemeToggle() { const [theme, setTheme] = useAtom(themeAtom)
return ( <button onClick={() => setTheme(prev => prev === 'light' ? 'dark' : 'light' )}> Current theme: {theme} </button> )}Atomの組織化
Section titled “Atomの組織化”- Atomはfeature単位でファイルを分割
- 関連するAtomは同じファイルにまとめる
- グローバルなAtomは
src/atoms/ディレクトリに配置