Managing global state in React applications doesn’t have to be complicated. Zustand is a lightweight state management library that simplifies the process with a minimalistic API and powerful features.
In this blog post, we’ll explore how Zustand works with a practical example: a todo list application built in TypeScript.
What Is Zustand?
Zustand (German for “state”) is a fast, flexible, and boilerplate-free state management library. Unlike Redux, Zustand avoids complexity, allowing you to focus on building features.
Key Features:
- Minimal API: Define and access state with ease.
- Built for React: Fully compatible with React’s reactivity model.
- TypeScript Ready: First-class TypeScript support for strongly typed stores.
- Efficient Updates: Components only re-render when their specific slice of state changes.
Installation
To get started, install Zustand using your package manager:
bashnpm install zustand
# or
yarn add zustand
Building a Todo List with Zustand
Let’s create a todo list application to see Zustand in action. We’ll handle adding, toggling, and removing todos, all managed in a single store.
Step 1: Create the Store
We’ll use Zustand’s create
function to define our store, complete with state and actions.
typescriptimport { 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
}
export const useTodoStore = create<TodoStore>((set) => ({
todos: [],
addTodo: (text) => set((state) => ({
todos: [ // Spread all, then add new todo
...state.todos, {
id: Date.now(),
text,
completed: false
}
]
})),
toggleTodo: (id) => set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? {
// Spread all properties, then toggle completed
...todo,
completed: !todo.completed
} : todo
)
})),
removeTodo: (id) => set((state) => ({
todos: state.todos.filter((todo) =>
// Filter out the todo with the matching ID
todo.id !== id
)
}))
}))
Here’s what’s happening:
-
todos
is our list of todo items. -
addTodo
adds a new todo with a unique ID. -
toggleTodo
toggles thecompleted
status of a todo by ID. -
removeTodo
removes a todo by ID.
Step 2: Use the Store in Components
Now, let’s build components that interact with our store.
Displaying Todos
typescriptimport React from "react"
import { useTodoStore } from "./todoStore"
import { FC } from "react"
const TodoList: FC = () => {
// Access the todos and actions from the store
const todos = useTodoStore((state) => state.todos)
const toggleTodo = useTodoStore((state) => state.toggleTodo)
const removeTodo = useTodoStore((state) => state.removeTodo)
return <ul>
{todos.map((todo) =>
<li key={todo.id}>
<span
onClick={() => toggleTodo(todo.id)}
style={{
textDecoration: todo.completed
? "line-through"
: "none",
cursor: "pointer"
}}
>
{todo.text}
</span>
<button onClick={() => removeTodo(todo.id)}>
Remove
</button>
</li>
)}
</ul>
}
export default TodoList
Adding Todos
typescriptimport React, { useState } from "react"
import { useTodoStore } from "./todoStore"
import { FC } from "react"
const AddTodo: FC = () => {
const [text, setText] = useState("")
const addTodo = useTodoStore((state) => state.addTodo)
const handleAdd = () => {
if (text.trim()) {
addTodo(text)
setText("")
}
}
return <div>
<input
type="text"
value={text}
onChange={(event) => setText(event.target.value)}
placeholder="Add a new todo"
/>
<button onClick={handleAdd}>
Add Todo
</button>
</div>
}
export default AddTodo
Step 3: Bringing It All Together
Finally, combine the TodoList
and AddTodo
components into a single app:
typescriptimport React from "react"
import TodoList from "./TodoList"
import AddTodo from "./AddTodo"
import { FC } from "react"
const App: FC = () => {
return <div>
<h1>Todo List</h1>
<AddTodo />
<TodoList />
</div>
}
export default App
Why Use Zustand?
Zustand stands out for its simplicity and power. Here’s why it’s worth considering:
- No Boilerplate: Manage state and actions in one place.
- Performance: Avoid unnecessary renders with selectors.
- TypeScript Support: Strongly type your stores for better developer experience.
- Scalable: Works for both small projects and complex apps.
Conclusion
Zustand is a fantastic choice for React developers who want simple yet powerful state management. Whether you’re working on a small project or scaling a larger application, Zustand offers the flexibility you need without the complexity.
To learn more, check out the Zustand GitHub Repository.
Ready to simplify your state management? Give Zustand a try!