useUndoRedoState
Manages state with bounded undo and redo history.
About
useUndoRedoState has a useState-like setter and separate past and future stacks. It is useful for editors and other interactions where users need to reverse and reapply changes while bounding memory use.
Example
import { useUndoRedoState } from "rooks";
export default function EditableCount() {
const [count, setCount, controls] = useUndoRedoState(0, { maxDepth: 20 });
return (
<section>
<p>Count: {count}</p>
<button type="button" onClick={() => setCount((value) => value + 1)}>
Increment
</button>
<button
type="button"
disabled={!controls.isUndoPossible}
onClick={controls.undo}
>
Undo
</button>
<button
type="button"
disabled={!controls.isRedoPossible}
onClick={controls.redo}
>
Redo
</button>
<button type="button" onClick={controls.clearAll}>
Clear history
</button>
</section>
);
}Parameters
initialState: T— required initial value.options?: { maxDepth?: number }— controls how many past values are retained.maxDepthdefaults to100. The implementation does not validate this value; use a non-negative integer.
Return value
The hook returns [state, setState, controls]:
state: T— the current value.setState— accepts a value or(previousState: T) => T, like React state setters.controls.undo()andcontrols.redo()— move one value through the past and future stacks. They do nothing at the corresponding boundary.controls.isUndoPossibleandcontrols.isRedoPossible— current boolean availability flags.controls.clearUndoStack(),controls.clearRedoStack(), andcontrols.clearAll()— remove history without changing the current value.controls.canUndo()andcontrols.canRedo()— deprecated callback forms of the availability flags. Prefer theis*Possiblebooleans.
Behavior and lifecycle
Every setter call records the previous value—even when the next value compares equal—and clears the redo stack. Once the past exceeds maxDepth, the oldest entry is removed. Undo and redo callbacks update their opposing stack so navigation can continue in either direction.
The implementation uses undefined to mean “no history entry.” If undefined is a meaningful state value, it cannot be restored through undo or redo; use an explicit sentinel object or another state representation instead. The hook has no external subscriptions or cleanup work.
Changing initialState after mount does not reset the current value or history.
Compatibility and accessibility
This hook uses only React state and can render during SSR. Bind button disabled states to the availability booleans and preserve familiar undo/redo keyboard behavior when integrating it into an editor.
Related
- useTimeTravelState adds multi-step navigation, history lengths, and reset controls.
- useUndoState keeps a single backward history stack.