実践的な Todo アプリで学ぶ Jotai の応用パターン
localStorage に状態を永続化
フィルタリング、統計情報の計算
追加・切替・削除の書き込み操作
ローカルとグローバルの使い分け
Todo がありません
jotai/utilsに含まれるユーティリティです。 ブラウザをリロードしても状態が保持されます。
import { atomWithStorage } from "jotai/utils";
// 第1引数: localStorage のキー名
// 第2引数: 初期値
const todosAtom = atomWithStorage(
"jotai-todos",
[]
);書き込み専用の派生 Atom を「アクション」として使うと、 ロジックを Atom 層に移動でき、コンポーネントがシンプルになります。
// 追加アクション
const addTodoAtom = atom(
null,
(_get, set, text: string) => {
const newTodo = {
id: crypto.randomUUID(),
text, completed: false
};
set(todosAtom, (prev) =>
[...prev, newTodo]
);
}
);この Todo アプリでの使い分け
// ローカル: 入力中のテキスト(このコンポーネントだけ)
const [text, setText] = useState("");
// グローバル: Todo リスト(複数コンポーネントで共有)
const addTodo = useSetAtom(addTodoAtom);┌─────────────────────────────────────────────┐
│ Primitive Atoms │
│ │
│ todosAtom ─────── atomWithStorage │
│ (Todo[]) (localStorage に保存) │
│ │
│ filterAtom ────── atom("all") │
│ ("all"|"active"|"completed") │
├─────────────────────────────────────────────┤
│ Derived Atoms (読み取り専用) │
│ │
│ filteredTodosAtom ← todosAtom + filterAtom │
│ todoStatsAtom ← todosAtom │
├─────────────────────────────────────────────┤
│ Action Atoms (書き込み専用) │
│ │
│ addTodoAtom → todosAtom │
│ toggleTodoAtom → todosAtom │
│ removeTodoAtom → todosAtom │
│ clearCompletedAtom → todosAtom │
└─────────────────────────────────────────────┘ここまでで、Jotai の主要なパターンをすべて学びました。