Blogs
Zustand with TypeScript and React
Zustand with TypeScript and React
January 1, 2022
Zustand Practices
- Separating concerns through slices
// createBearSlice.tsimport { GetState, SetState } from "zustand";import { MyState } from "./useStore";export interface BearSlice {eatFish: () => void;}const createBearSlice = (set: SetState<MyState>, get: GetState<MyState>) => ({eatFish: () => {set((prev) => ({ fishes: prev.fishes > 1 ? prev.fishes - 1 : 0 }));},});export default createBearSlice;
// createFishSlice.tsimport { GetState, SetState } from "zustand";import { MyState } from "./useStore";export interface FishSlice {fishes: number;repopulate: () => void;}const maxFishes = 10;const createFishSlice = (set: SetState<MyState>, get: GetState<MyState>) => ({fishes: maxFishes,repopulate: () => {set((prev) => ({ fishes: maxFishes }));},});export default createFishSlice;
- Consume those slices in a
useStore
hook
// useStore.tsimport create from "zustand";import createBearSlice, { BearSlice } from "./createBearSlice";import createFishSlice, { FishSlice } from "./createFishSlice";export type MyState = BearSlice & FishSlice;const useStore =create <MyState >((set, get) => ({...createBearSlice(set, get),...createFishSlice(set, get),}));export default useStore;
- Sample usage in a component
// App.jsimport useStore from "./store/useStore";export default function Mountain() {const fishes = useStore((state) => state.fishes);const eatFish = useStore((state) => state.eatFish);const repopulate = useStore((state) => state.repopulate);return (<div><p>Fishes: {fishes}</p><button onClick={eatFish}>Eat</button><button onClick={repopulate}>Repopulate</button></div>);}