2

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),
})))
ohthepain
  • 2,004
  • 3
  • 19
  • 30

0 Answers0