Rooks
HooksState History & Time Travel

useUndoState

Manages state with a bounded, one-directional undo history.

About

useUndoState resembles useState but keeps prior values and exposes an undo function. Choose it for simple one-way rollback where redoing or jumping within history is unnecessary.

Example

import { useUndoState } from "rooks";

export default function UndoableCounter() {
  const [value, push, undo] = useUndoState(0, { maxSize: 30 });

  return (
    <section>
      <p>Current value: {value}</p>
      <button
        type="button"
        onClick={() => push((current: number) => current + 1)}
      >
        Increment
      </button>
      <button type="button" onClick={undo}>
        Undo
      </button>
    </section>
  );
}

Parameters

  • defaultValue: T — required initial value. A function cannot be used as the state value because functions are interpreted as updater callbacks by push.
  • options?: { maxSize?: number } — sets the maximum number of earlier values retained for undo. maxSize defaults to 100.

The option object is merged with its defaults, so passing a new object each render is harmless but unnecessary.

Return value

The result is [value, push, undo]:

  • value: T — the newest stored value.
  • push(next) — adds a direct value or the result of (currentValue: T) => T to the front of the history.
  • undo() — removes the current entry and reveals the previous one. It does nothing when only the initial entry remains.

There is no redo function and no canUndo flag.

Behavior and lifecycle

History is stored newest-first in React state. At its limit, pushing a value discards the oldest retained entry. Pushing an equal value still adds a history step. The hook creates no subscriptions or external resources, and its history is discarded on unmount.

Changing defaultValue or maxSize does not reset existing history; a new maxSize affects subsequent pushes.

Compatibility and accessibility

The hook has no browser dependency and can render during SSR. Because it does not report whether undo is available, applications that must disable an unavailable undo control should track that condition separately or use useUndoRedoState.

On this page