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:
- Open your application in a browser.
- Open the Redux DevTools extension in your browser. (You may need to install it if you haven’t already, from the Chrome Extension store).
- 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"
);
},
});