Zustand slice pattern with property name as slice wrapper

13 Views Asked by At

I'm following the Zustand slice pattern:

import { create, StateCreator } from 'zustand'

interface BearSlice {
  bears: number
  addBear: () => void
  eatFish: () => void
}

interface FishSlice {
  fishes: number
  addFish: () => void
}

interface SharedSlice {
  addBoth: () => void
  getBoth: () => void
}

const createBearSlice: StateCreator<BearSlice & FishSlice, [], [], BearSlice> = (set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
  eatFish: () => set((state) => ({ fishes: state.fishes - 1 })),
})

const createFishSlice: StateCreator<BearSlice & FishSlice, [], [], FishSlice> = (set) => ({
  fishes: 0,
  addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})

const createSharedSlice: StateCreator<BearSlice & FishSlice, [], [], SharedSlice> = (set, get) => ({
  addBoth: () => {
    // you can reuse previous methods
    get().addBear()
    get().addFish()
    // or do them from scratch
    // set((state) => ({ bears: state.bears + 1, fishes: state.fishes + 1 })
  },
  getBoth: () => get().bears + get().fishes,
})

const useBoundStore = create<BearSlice & FishSlice & SharedSlice>()((...a) => ({
  ...createBearSlice(...a),
  ...createFishSlice(...a),
  ...createSharedSlice(...a),
}))

I would like to get the slice root propery in front of each slice like so:

const useBoundStore = create<{ bearSlice: BearSlice; fishSlice: FishSlice, sharedSlice: SharedSlice }>()((...a) => ({
  bearSlice: createBearSlice(...a),
  fishSlice: createFishSlice(...a),
  sharedSlice: createSharedSlice(...a),
}))

I could insert the root property inside the slice, but that would require me to update all sets such as:

set((state) => ({ bears: state.bears + 1 }))

to

set((state) => ({ bearSlice: { ...state.bearSlice, bears: state.bearSlice.bears + 1 }} ))

and that is impossible considering my real code base.

Any suggestions?

0

There are 0 best solutions below