TL;DR does anybody have an example of using Zustand with Zundo with slices?
I started implementing Zustand undo using Zundo and then realized that I have multiple stores. So I decided to refactor to use slices and a single store.
So far I have zundo working in one store, and have implemented another store as a slice. The next step in my plan was to then get one of the stores working with both and got stuck there.
I added undo using the middleware approach. Basically you just wrap your state creator in a call to undoMiddleware():
export const useSequenceStore = create<SequenceState>(
undoMiddleware((set) => ({
sequence: new Sequence({}),
setTempo: (tempo: number) => set(produce(draft => { draft.sequence.tempo = tempo })),
setDivision: (division: number) => set(produce(draft => {draft.sequence.division = division})),
setLength: (length: number) => set(produce(draft => { draft.sequence.length = length })),
loadSequence: (sequence: Sequence) => set( state => ({ sequence: loadSequence(sequence) })),
setName: (name: string) => set(produce(draft => { draft.sequence.name = name })),
setText: (text: string) => set(produce(draft => { draft.sequence.text = text })),
setNumSteps: (numSteps: number) => set(produce(draft => {setNumSteps(draft.sequence, numSteps)})),
setEnvelopeLength: (envelopeId: string, length: number) => set(produce(draft => {setEnvelopeLength(draft.sequence, envelopeId, length)})),
setSkin: (skin: Skin) => set(produce(draft => {draft.sequence.skin = skin})),
setMidiSettings: (midiSettings: MidiSettings) => set(produce(draft => { draft.sequence.midiSettings = {...midiSettings}})),
setEnvelopeLocked: (envelopeId: string, locked: boolean) => set(produce(draft => {setEnvelopeLocked(draft.sequence, envelopeId, locked)})),
setStepNote: (stepNum: number, noteNum: number) => set(produce(draft => { setStepNote(draft.sequence, stepNum, noteNum)})),
setStepVelocity: (stepNum: number, velocity: number) => set(produce(draft => { setStepVelocity(draft.sequence, stepNum, velocity)})),
setStepGateLength: (stepNum: number, gateLength: number) => set(produce(draft => { setStepGateLength(draft.sequence, stepNum, gateLength)})),
createEnvelope: (controller: ControllerInfo) => set(produce(draft => {createEnvelope(draft.sequence, controller)})),
deleteEnvelope: (envelopeId) => set(produce(draft => deleteEnvelope(draft.sequence, envelopeId))),
setEnvelopeValue: (envelopeId: string, controller: ControllerInfo, value: number) => set(produce(draft => {setEnvelopeValue(draft.sequence, envelopeId, controller, value)})),
setCurrentEnvelopeId: (envelopeId: string) => set(produce(draft => { draft.sequence.currentEnvelopeId = envelopeId} )),
addEnvelopePoint: (envelopeId: string, time: number, value: number) => set(produce(draft => {addEnvelopePoint(draft.sequence, envelopeId, time, value)})),
deleteEnvelopePoint: (envelopeId: string, time: number, value: number) => set(produce(draft => { deleteEnvelopePoint(draft.sequence, envelopeId, time, value)})),
moveEnvelopePoint: (envelopeId: string, pointnum: number, time: number, value: number) => set(produce(draft => {moveEnvelopePoint(draft.sequence, envelopeId, pointnum, time, value)})),
})));
I have converted my PositionStore to a PositionSlice:
import create from "zustand";
import {createPositionSlice, PositionSlice} from "./position-store";
export const useBoundStore = create<PositionSlice>()((...a) => ({
... createPositionSlice(...a),
}))
Wrong approach? How do I add the undoMiddleware call to that? I have tried in various forms but I think the middleware is designed to apply to a slice.
export const useBoundStore = create<PositionSlice>()((...a) => undoMiddleware(({
... createPositionSlice(...a),
})))