お疲れ様です!IT業界で働くアライグマです!
結論から言うと、jotaiはSuspense時代の状態管理に最適なライブラリです。React 18以降の開発で特に威力を発揮します。
「Reduxは大げさだし、Context APIはパフォーマンスが心配…」そんな悩みを抱えているReact開発者は多いのではないでしょうか。複数のReactプロジェクトに関わる中で、状態管理ライブラリの選定で何度も議論を重ねてきた経験があります。
本記事では、jotaiを使ったSuspense時代の状態管理パターンを、実装例とともに解説します。非同期データ取得、エラーハンドリング、そしてチーム開発で意識すべきポイントまで、実践的な内容をお届けします。
jotaiとは何か:アトムベースの状態管理
jotaiは、日本語の「状態」を意味する言葉を名前に持つ、アトムベースの状態管理ライブラリです。公式ドキュメントによると、「Primitive and flexible state management for React」をコンセプトに設計されています。
jotaiの特徴とメリット
jotaiの最大の特徴は、ボトムアップなアプローチです。小さなアトム(状態の単位)を組み合わせて、必要な状態を構築していきます。
import { atom, useAtom } from 'jotai'
// アトムの定義(プリミティブな値)
const countAtom = atom(0)
// 派生アトム(他のアトムから計算)
const doubleCountAtom = atom((get) => get(countAtom) * 2)
// コンポーネントでの使用
function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
)
}
Reduxのようなボイラープレートが不要で、TypeScriptとの親和性も高いのがポイントです。
PjMとして見ると、jotaiは学習コストが低く、チームへの導入がスムーズという利点があります。useState感覚で書けるため、Reactの基礎知識があればすぐに使い始められます。
Cursorとローカルでのllm活用完全ガイドでも触れていますが、開発ツールの選定では「チーム全体の生産性」を考慮することが重要です。
IT女子 アラ美Suspenseとの統合:非同期データ取得の新しいパターン
React 18で正式に導入されたSuspenseは、非同期処理の待機を宣言的に扱える機能です。jotaiはこのSuspenseとネイティブに統合されています。
非同期アトムの基本パターン
jotaiでは、アトムのread関数にasync関数を渡すだけで、Suspense対応の非同期アトムを作成できます。
import { atom, useAtom } from 'jotai'
// ユーザーデータを取得する非同期アトム
const userAtom = atom(async () => {
const response = await fetch('/api/user')
if (!response.ok) throw new Error('Failed to fetch user')
return response.json()
})
// Suspense境界内で使用
function UserProfile() {
const [user] = useAtom(userAtom)
// userは必ず解決済みの値
return <div>Welcome, {user.name}</div>
}
// 親コンポーネントでSuspenseをラップ
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</Suspense>
)
}
この パターンの利点は、コンポーネント内でローディング状態を意識する必要がないことです。useEffectとuseStateの組み合わせによる従来のパターンと比較すると、コードがシンプルになります。
あるReactプロジェクトでは、この変更によりコンポーネントのコード行数が平均30%削減されました。
GitHub Copilotカスタムエージェント設定ガイドで紹介したように、AIコーディング支援との相性も良好です。



エラーハンドリング:Error Boundaryとの連携
非同期処理にはエラーハンドリングが不可欠です。jotaiでは、Error Boundaryと組み合わせることで、宣言的なエラーハンドリングを実現できます。
Error Boundaryの実装
import { ErrorBoundary } from 'react-error-boundary'
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>エラーが発生しました: {error.message}</p>
<button onClick={resetErrorBoundary}>再試行</button>
</div>
)
}
function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => {
// リセット時の処理(キャッシュクリアなど)
}}
>
<Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</Suspense>
</ErrorBoundary>
)
}
リトライパターンの実装
jotaiのuseSetAtomと組み合わせることで、エラー時のリトライ機能を実装できます。
import { atom, useAtom, useSetAtom } from 'jotai'
// リフレッシュ用のトリガーアトム
const refreshTriggerAtom = atom(0)
// データ取得アトム(トリガーに依存)
const dataAtom = atom(async (get) => {
get(refreshTriggerAtom) // 依存関係を作成
const response = await fetch('/api/data')
if (!response.ok) throw new Error('Network error')
return response.json()
})
// リフレッシュ関数を使用するコンポーネント
function DataDisplay() {
const [data] = useAtom(dataAtom)
const refresh = useSetAtom(refreshTriggerAtom)
return (
<div>
<pre>{JSON.stringify(data, null, 2)}</pre>
<button onClick={() => refresh(n => n + 1)}>
データを再取得
</button>
</div>
)
}
このパターンは、SWRやReact Queryのようなデータフェッチングライブラリと似た使い勝手を提供します。
NISTパスワードガイドライン2025で触れたセキュリティの観点からも、エラーメッセージの出力には注意が必要です。



ケーススタディ:実際のプロジェクトでの導入事例
ここでは、あるプロジェクトでjotaiを導入した事例を紹介します。
導入前の状況(Before)
- React 17 + Redux Toolkit で構築された管理画面
- コンポーネント数: 約150個
- 状態管理関連のコード: 約3,000行
- useEffect + useState による非同期処理が散在
実施した行動(Action)
- React 18へのアップグレード
- 新規機能からjotaiを段階的に導入
- 既存のReduxスライスを順次jotaiアトムへ移行
- Suspense境界を戦略的に配置
導入後の結果(After)
- 状態管理関連のコード: 約1,800行(40%削減)
- ローディング/エラー処理の重複コード: 約70%削減
- 新機能開発時の状態管理設計時間: 約50%短縮


ハマりポイント
移行時に遭遇した問題として、SSR(Server-Side Rendering)との相性がありました。jotaiはクライアントサイド前提の設計のため、Next.jsのApp Routerと組み合わせる際は’use client’ディレクティブの配置に注意が必要でした。
ローカルNotebookLMセットアップガイドでも触れましたが、新技術の導入には段階的なアプローチが有効です。



チーム開発での実践パターン
アトム設計のベストプラクティス
チーム開発では、アトムの命名規則と配置ルールを事前に決めておくことが重要です。
// atoms/user.ts - 機能ごとにファイルを分割
import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
// プリミティブアトムには〜Atomサフィックス
export const userIdAtom = atom<string | null>(null)
// 永続化が必要なアトムにはatomWithStorageを使用
export const themeAtom = atomWithStorage('theme', 'light')
// 派生アトムには〜DerivedAtomサフィックス
export const isLoggedInDerivedAtom = atom(
(get) => get(userIdAtom) !== null
)
// 非同期アトムには〜AsyncAtomサフィックス
export const userDataAsyncAtom = atom(async (get) => {
const userId = get(userIdAtom)
if (!userId) return null
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
テスト戦略
jotaiはテストが書きやすい設計になっています。Providerを使ってアトムの初期値を注入できるため、コンポーネントテストが容易です。
import { render, screen } from '@testing-library/react'
import { Provider } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
// テスト用のHydrateコンポーネント
function HydrateAtoms({ initialValues, children }) {
useHydrateAtoms(initialValues)
return children
}
test('ユーザー名が表示される', () => {
render(
<Provider>
<HydrateAtoms initialValues={[[userAtom, { name: 'テストユーザー' }]]}>
<UserProfile />
</HydrateAtoms>
</Provider>
)
expect(screen.getByText('Welcome, テストユーザー')).toBeInTheDocument()
})
PhpStorm AI CLI統合ガイドで紹介したように、テスト自動化は開発効率に直結します。
本記事で解説したようなAI技術を、基礎から体系的に身につけたい方は、以下のスクールも検討してみてください。
| 比較項目 | DMM 生成AI CAMP | Aidemy Premium |
|---|---|---|
| 目的・ゴール | ビジネス活用・効率化非エンジニア向け | エンジニア転身・E資格Python/AI開発 |
| 難易度 | プロンプト作成中心 | コード記述あり |
| 補助金・給付金 | リスキリング補助金対象 | 教育訓練給付金対象 |
| おすすめ度 | 今の仕事に活かすなら | AIエンジニアになるなら |
| 公式サイト | 詳細を見る | 詳細を見る |



まとめ
本記事では、jotaiを使ったReact Suspense時代の状態管理について解説しました。
- jotaiはアトムベースの軽量な状態管理ライブラリで、学習コストが低い
- Suspenseとネイティブに統合されており、非同期処理が宣言的に書ける
- Error Boundaryと組み合わせることで、エラーハンドリングもシンプルになる
- チーム開発では、命名規則とファイル配置のルールを事前に決めることが重要
まずは小さな機能からjotaiを試してみてください。Suspenseの恩恵を体感できれば、プロジェクト全体への展開を検討する価値があります。
React開発のスキルアップは、エンジニアとしての市場価値を高める確実な投資です。新しい技術に触れ続けることで、キャリアの選択肢を広げていきましょう。














