DEV Community

Cover image for Zustand: A Lightweight State Management Library (No Boilerplate Needed)
Salman Sadik Siddiquee
Salman Sadik Siddiquee

Posted on

Zustand: A Lightweight State Management Library (No Boilerplate Needed)

Zustand is a simple and powerful state management library for React applications.
Unlike Redux, it has no heavy boilerplate, no reducers, no actions, and no complicated setup.
You just create a store using the create function and start using it immediately.

Here’s a basic todo store:

import { create } from 'zustand';

const useTodoStore = create(

    (set) => ({
        todos: [
            {
                id: crypto.randomUUID(),
                text: 'Learn React',
                completed: false,
            },
            {
                id: crypto.randomUUID(),
                text: 'Learn Zustand',
                completed: false,
            },

        ],
    })

);

export default useTodoStore;
Enter fullscreen mode Exit fullscreen mode

Consuming the Store in a Component

 const todos = useTodoStore((state) => state.todos);
Enter fullscreen mode Exit fullscreen mode

Todo App

Need to add a new todo ?

To insert a new todo item into the store, you create an addTodo function inside your Zustand store. This function receives the new todo text and then updates the state using Zustand’s set function.

Zustand encourages immutable updates, meaning you should never directly mutate the previous state. You can also use immer for immutable updates easily. Instead, you create a new array by spreading the existing todos and adding the new one at the end.

import { create } from 'zustand';

const useTodoStore = create(

    (set) => ({
        todos: [],
        addTodo: (text) =>
            set((state) => ({
                todos: [
                    ...state.todos,
                    { id: crypto.randomUUID(), text, completed: false },
                ],
            })),
    })

);

export default useTodoStore;
Enter fullscreen mode Exit fullscreen mode

Use the addTodo function in a component

   const addTodo = useTodoStore((state) => state.addTodo);

    const handleSubmit = (e) => {
        e.preventDefault();
        if (text.trim()) {
            addTodo(text.trim());
            setText('');
        }
    };
Enter fullscreen mode Exit fullscreen mode

Persistance

You can persist the data in the local storage using the persist middleware that comes from zustand/middleware, like this

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useTodoStore = create(

    persist(
        (set) => ({
            todos: [],
            addTodo: (text) =>
                set((state) => ({
                    todos: [
                        ...state.todos,
                        { id: crypto.randomUUID(), text, completed: false },
                    ],
                })),
        })
    )
);

export default useTodoStore;
Enter fullscreen mode Exit fullscreen mode

local storage

By default, the persist middleware does not assign a storage key.
To customize it, you can pass a second configuration object to persist and set a name property, which becomes the key used in localStorage.


import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useTodoStore = create(

    persist(
        (set) => ({
            todos: [],
            addTodo: (text) =>
                set((state) => ({
                    todos: [
                        ...state.todos,
                        { id: crypto.randomUUID(), text, completed: false },
                    ],
                })),
        }),
        {
            name: 'todo-storage',
        }
    )
);

export default useTodoStore;
Enter fullscreen mode Exit fullscreen mode

local storage

Devtools

Zustand also supports Redux DevTools using the devtools middleware.
This lets you inspect state changes, time travel, and debug more easily.

The set function can accept three arguments:

  • A function that returns the updated state

  • A boolean indicating whether to replace the entire state

  • A string that names the action (useful for DevTools)

import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';

const useTodoStore = create(
    devtools(
        persist(
            (set) => ({
                todos: [],
                filter: 'all',
                addTodo: (text) =>
                    set(
                        (state) => ({
                            todos: [
                                ...state.todos,
                                { id: crypto.randomUUID(), text, completed: false },
                            ],
                        }),
                        false,           // replace state?
                        "addTodo"        // action name for DevTools
                    ),
            }),
            { name: 'todo-storage' }
        ),
        { name: "TodoStore" }
    )
);

export default useTodoStore;

Enter fullscreen mode Exit fullscreen mode

Now you can debug with the Redux devtool.

redux devtool

Summary

  • Zustand is a minimal state manager without boilerplate.

  • You create a store using create.

  • State consumption is simple: useStore((state) => state.value).

  • You can add actions like addTodo that modify state safely.

  • Persist middleware stores your data in localStorage.

    • DevTools middleware integrates with Redux DevTools for debugging.

Zustand is perfect for React developers who want clean, predictable, and easy-to-maintain global state with minimal setup.

GitHub Repository & Live Demo

GitHub Repo:
👉 todo-app-zustand

Live Demo:
👉 Live Link

Top comments (0)