Zustand Tutorial
Tutorial Overview
Welcome to the comprehensive Zustand tutorial! This guide will take you from beginner to advanced, teaching you everything you need to know about state management with Zustand.
Lesson 1: Introduction to Zustand
Zustand is a lightweight state management library for React that provides:
- Simple and intuitive API
- No boilerplate code required
- Great TypeScript support
- Excellent performance with automatic optimization
- Small bundle size (less than 1KB)
Why Choose Zustand?
Compared to other state management solutions like Redux or MobX, Zustand offers a simpler API with less boilerplate while maintaining powerful features and excellent performance.
Lesson 2: Creating Your First Store
Let's create a simple todo list application:
import { create } from 'zustand'
interface Todo {
id: number
text: string
completed: boolean
}
interface TodoStore {
todos: Todo[]
addTodo: (text: string) => void
toggleTodo: (id: number) => void
removeTodo: (id: number) => void
}
const useTodoStore = create<TodoStore>((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)
})),
}))Lesson 3: Using the Store in Components
function TodoList() {
const todos = useTodoStore((state) => state.todos)
const addTodo = useTodoStore((state) => state.addTodo)
const toggleTodo = useTodoStore((state) => state.toggleTodo)
const removeTodo = useTodoStore((state) => state.removeTodo)
const [input, setInput] = useState('')
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (input.trim()) {
addTodo(input)
setInput('')
}
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a todo..."
/>
<button type="submit">Add</button>
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}>
{todo.text}
</span>
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
)
}Lesson 4: Async Actions & Advanced Patterns
Async Actions
Handling async actions in Zustand is simple - just make your action async!
const useStore = create((set) => ({
data: null,
loading: false,
error: null,
fetchData: async () => {
set({ loading: true, error: null })
try {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
set({ data, loading: false })
} catch (error) {
set({ error: error.message, loading: false })
}
}
}))Computed Values
Create derived state with selectors:
const useStore = create((set) => ({
todos: [],
// ... actions
}))
// In your component
const completedCount = useStore(
(state) => state.todos.filter(t => t.completed).length
)
const totalCount = useStore((state) => state.todos.length)Next Steps
Continue learning with these topics:
- Middleware for persistence and devtools
- Testing Zustand stores
- Advanced TypeScript patterns
- Performance optimization techniques
- Integration with other libraries