history

Tracks state history and enables undo / redo / reset. Every state change, however it happens (set, merge, or any plugin method), is recorded, because the plugin records via this.subscribe() rather than hooking any particular write path.

Basic usage

import { createStore } from "@kintools/store-core";
import { history } from "@kintools/store-plugins";
 
const store = createStore({ count: 0 })
  .use({
    increment(n: number): void {
      this.merge((s) => ({ count: s.count + n }));
    },
  })
  .use("history", history());
 
store.increment(1); // count = 1
store.increment(1); // count = 2
 
store.history.canUndo(); // true
store.history.undo(); // count = 1
store.history.redo(); // count = 2
store.history.reset(); // count = 0

Plugin methods

MethodDescription
canUndo()Returns true if there is a past state to undo to
canRedo()Returns true if there is a future state to redo to
undo()Moves back one step; returns true if moved, false if already at start
redo()Moves forward one step; returns true if moved, false if already at end
reset()Restores the baseline state and clears the history
rebase()Makes the current state the new undo floor, discarding prior history

Options

OptionTypeDefaultDescription
limitnumberInfinityMax snapshots to keep. When exceeded, the oldest is dropped.
.use('history', history({ limit: 50 }))

Composing with persist

After async hydration, call rebase() so undo and reset don't step back to the pre-hydration state:

const store = createStore({ items: [] as string[] })
  .use("persist", persist({ key: "items" }))
  .use("history", history())
  .use({
    add(item: string): void {
      this.merge((s) => ({ items: [...s.items, item] }));
    },
  });
 
await store.persist.hydrationComplete();
store.history.rebase();