Skip to main content

Zustand

Overview​

Zustand has been gaining popularity as a state management library for React applications. Its simplicity, minimal boilerplate, and seamless integration with React Hooks have made it an attractive alternative to more established libraries like Redux.

Quick Setup​

Define​

type bearStoreState = { bears: number };

type bearStoreActions = {
addABear: () => void;
};

type StoreState = bearStoreState & bearStoreActions;

export const useBearStore = create<StoreState>()((set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
}));

Usage​

const bear = useBearStore((state) => state.bears);
const addABear = useBearStore((state) => state.addABear);

Slicing the store into smaller bearStoreState​

Define types​

typing.ts
export type BearSlice = {
bears: number;
addABear: () => void;
};

export type FishSlice = {
fishes: number;
addAFish: () => void;
};

export type StoreState = BearSlice & FishSlice;

Slices​

bearSlice.ts.ts
import { StateCreator } from "zustand";
import { BearSlice, StoreState } from "./typing";

export const createBearSlice: StateCreator<StoreState, [], [], BearSlice> = (
set,
get
) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
});
fishSlice.ts.ts
import { StateCreator } from "zustand";
import { FishSlice, StoreState } from "./typing";

export const createFishSlice: StateCreator<StoreState, [], [], FishSlice> = (
set,
get
) => ({
fishes: 0,
addAFish: () => set({ fishes: get().fishes + 1 }),
});

Store​

index.ts
import { create } from "zustand";
import { createBearSlice } from "./bearSlice";
import { createFishSlice } from "./fishSlice";
import { StoreState } from "./typing";

export const useBearStore = create<StoreState>()((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}));

Devtools with time-travel debugging​

Config Devtools​

import { devtools } from "zustand/middleware";

export const useBearStore = create<StoreState>()(
devtools((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}))
);

Add action name​

export const createBearSlice: StateCreator<
StoreState,
[["zustand/devtools", never]],
[],
BearSlice
> = (set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }, false, 'addABear')
});
note

If you have some middlewares then replace StateCreator<MyState, [], [], MySlice> with StateCreator<MyState, Mutators, [], MySlice>. For example, if you are using devtools then it will be StateCreator<MyState, [["zustand/devtools", never]], [], MySlice>. See the "Middlewares and their mutators reference" section for a list of all mutators.

Once your store is configured with the devtools middleware:

  1. Open your application in a browser.
  2. Open the Redux DevTools extension in your browser. (You may need to install it if you haven’t already, from the Chrome Extension store).
  3. You should see your Zustand store appear in the DevTools with actions you can time-travel, inspect, and reset.

Integrate Immer for complex state management​

Config Immer​

import { immer } from "zustand/middleware/immer";

export const useBearStore = create<StoreState>()(
devtools(
immer((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}))
)
);

Update Slices​

import { StateCreator } from "zustand";
import { BearSlice, StoreState } from "./typing";

export const createBearSlice: StateCreator<
StoreState,
[["zustand/devtools", never], ["zustand/immer", never]],
[],
BearSlice
> = (set) => ({
bears: 0,
addABear: () => {
set(
(state) => {
state.bears += 1;
},
false,
"addABear"
);
},
});

codesandbox demo