Zustand

Language: JavaScript

State Management

Zustand was created by Jotai and React community contributors to offer an alternative to heavier state management libraries like Redux. It emphasizes simplicity, ease of use, and minimalistic design while being highly performant and flexible for both small and large applications.

Zustand is a small, fast, and scalable state management library for React. It provides a simple API to create global state stores with minimal boilerplate, using hooks for accessing and updating state.

Installation

npm: npm install zustand
yarn: yarn add zustand

Usage

Zustand allows you to create a store that holds your global state. Components can read from and write to the store using hooks. It supports derived state, middleware, and persistence without forcing a specific architecture.

Creating a simple store

import create from 'zustand';

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
  decrement: () => set(state => ({ count: state.count - 1 }))
}));

Defines a store with a `count` state and functions to increment and decrement it.

Using the store in a component

function Counter() {
  const { count, increment, decrement } = useStore();
  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  );
}

Accesses state and actions from the store inside a React component.

Derived state

const useStore = create(set => ({
  count: 0,
  double: () => set(state => ({ count: state.count * 2 }))
}));

const doubledCount = useStore(state => state.count * 2);

Demonstrates creating derived values from the store’s state.

Middleware example

import { persist } from 'zustand/middleware';
const useStore = create(persist(
  set => ({ count: 0, increment: () => set(state => ({ count: state.count + 1 })) }),
  { name: 'counter-storage' }
));

Adds persistence to the store so state is saved in localStorage.

Combining multiple actions

const useStore = create(set => ({
  count: 0,
  incrementBy: (n) => set(state => ({ count: state.count + n })),
  reset: () => set({ count: 0 })
}));

Shows multiple actions including parameterized state updates and resetting state.

Error Handling

State not updating in component: Ensure you are using the hook returned by the store and not a stale reference. Destructure state inside the component.
Performance issues with large state: Split state into multiple smaller stores and select only needed slices with hooks.
Persisted state not working: Check that the `persist` middleware is correctly applied and browser localStorage is accessible.

Best Practices

Use small, focused stores for different concerns rather than one large global store.

Leverage hooks to read only the parts of state needed by a component to avoid unnecessary re-renders.

Use middleware like `persist` or `redux-devtools-extension` for debugging and persistence.

Keep state updates immutable even though Zustand allows direct mutation in set functions.

Encapsulate complex logic inside actions rather than inside components.