このチュートリアルで学ぶこと
✓ Zustandの基本
✓ ストア作成
✓ アクション定義
✓ セレクター
✓ ミドルウェア
Step 1: セットアップ
npm install zustand
Step 2: 基本的なストア
// store/counterStore.ts
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
Step 3: コンポーネントで使用
function Counter() {
const { count, increment, decrement, reset } = useCounterStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
Step 4: セレクターで最適化
// 必要な値のみ購読
function CountDisplay() {
const count = useCounterStore((state) => state.count);
return <p>Count: {count}</p>;
}
function CountActions() {
const increment = useCounterStore((state) => state.increment);
return <button onClick={increment}>+</button>;
}
Step 5: 複雑なストア
// store/todoStore.ts
import { create } from 'zustand';
interface Todo {
id: number;
text: string;
completed: boolean;
}
interface TodoState {
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
removeTodo: (id: number) => void;
}
export const useTodoStore = create<TodoState>((set) => ({
todos: [],
addTodo: (text) =>
set((state) => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }],
})),
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: (id) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
}));
Step 6: 永続化ミドルウェア
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export const useSettingsStore = create(
persist<SettingsState>(
(set) => ({
theme: 'light',
setTheme: (theme) => set({ theme }),
}),
{
name: 'settings-storage',
}
)
);
Step 7: 非同期アクション
interface UserState {
user: User | null;
loading: boolean;
fetchUser: (id: string) => Promise<void>;
}
export const useUserStore = create<UserState>((set) => ({
user: null,
loading: false,
fetchUser: async (id) => {
set({ loading: true });
try {
const res = await fetch(`/api/users/${id}`);
const user = await res.json();
set({ user, loading: false });
} catch {
set({ loading: false });
}
},
}));
まとめ
ZustandはReduxより軽量でシンプルな状態管理ライブラリです。Providerが不要で、セレクターによる最適化も簡単です。
← 一覧に戻る