Skip to content

useStateHistory

Custom useState that tracks and allows to use previous values.

Demo

INFO

The component has:

  • a counter useHistoryState variable with initialState=0 and memory=10.
  • a button to increment counter.
  • a button to increment counter and to disable history.
  • a button to disabled history.
  • a button to enable history.
  • a button to undo operation.
  • a button to redo operation.
  • an input and button to go at specified value.
  • a button to clear history.
Loading demo…
Show source code
tsx
import { useStateHistory } from "../../../..";

function UseStateHistory() {

	const [count, setCount, {go, presentPointer, history, trackUpdate, canRedo, canUndo, redo, undo, clear}] = useStateHistory(0, 10);

	return (<>
		<p>
			Count is {count}
		</p>
		<p>
			Current pointer is {presentPointer}
		</p>
		<p>
			History is {JSON.stringify(history)}
		</p>
		<div style={{ gridTemplateColumns: 'auto auto auto', justifyContent: 'center', display: 'grid', gap: '5px' }}>
			<button onClick={() => setCount((count) => (count + 1))}>
				increment
			</button>
			<button onClick={() => setCount((count) => {
				trackUpdate(false);
				return count + 1;
			})}>
				disableHistory and increment
			</button>
			<button onClick={() => trackUpdate(false)}>
				disable history
			</button>
			<button onClick={() => trackUpdate(true)}>
				enable history
			</button>
			<button onClick={() => clear()}>Clear</button>
			<button onClick={undo} disabled={!canUndo}>Undo</button>
			<button onClick={redo} disabled={!canRedo}>Redo</button>
			<button onClick={() => go(+(document.querySelector('#go') as HTMLInputElement).value)}>
				Go
				<input type='number' id='go' style={{ marginLeft: 35, maxWidth: 40 }} />
			</button>
		</div>
	</>);
}

UseStateHistory.displayName = "UseStateHistory";

export { UseStateHistory };

Types

StateHistoryControls

  • @template T - The type of the state value.

The history controls object returned as part of {@link UseStateHistoryResult} and {@link UseStateHistoryGetterResult}.

PropertyTypeRequiredDescription
historyreadonly T[]A read-only array of all recorded state snapshots, from oldest to most recent. The entry at presentPointer is the currently active state.
presentPointernumberThe index within history that corresponds to the current state. Moves backward on undo and forward on redo or a new state update.
trackUpdate(enable: boolean) => voidEnables or disables history recording. When called with false, state updates still trigger re-renders but are not added to history. Re-enable with true to resume recording.
canUndobooleantrue when there is at least one state snapshot before presentPointer that can be restored via undo.
canRedobooleantrue when there is at least one state snapshot after presentPointer that can be restored via redo.
undo() => voidMoves presentPointer one step backward in history and restores the corresponding state. No-op when canUndo is false.
redo() => voidMoves presentPointer one step forward in history and restores the corresponding state. No-op when canRedo is false.
go(index: number) => voidJumps directly to the state at the given index in history, updating presentPointer and restoring that snapshot.
clear(value?: T) => voidClears the entire history array. When value is provided, the cleared history is replaced with a single entry equal to value; otherwise the history is reset to the current state only.

UseStateHistoryProps

  • @template T - The type of the state value.

Parameters accepted by useStateHistory and useStateHistoryGetter.

PropertyTypeRequiredDescription
initialStateT \| (() => T)The initial state value. Accepts either a direct value or a lazy initializer function invoked only on the first render.
capacitynumber \| "no-limit"Maximum number of state snapshots retained in history: - "no-limit" (default) — All snapshots are retained indefinitely. - number — Once the limit is reached, the oldest snapshot is evicted to make room for the new one (FIFO).

UseStateHistoryResult

  • @template T - The type of the state value.

Return value of useStateHistory.

IndexTypeDescription
[0]TThe current state value, reactive — triggers a re-render when updated.
[1]Dispatch<SetStateAction<T>>A stable setter (same semantics as the setter returned by useState). Accepts either a new value or an updater function receiving the current state and returning the next.
[2]StateHistoryControls<T>The history controls object. See {@link StateHistoryControls}.

UseStateHistoryGetterResult

  • @template T - The type of the state value.

Return value of useStateHistoryGetter.

IndexTypeDescription
[0]TThe current state value, reactive — triggers a re-render when updated.
[1]Dispatch<SetStateAction<T>>A stable setter (same semantics as the setter returned by useState). Accepts either a new value or an updater function receiving the current state and returning the next.
[2]() => TA stable getter that returns the current state value synchronously without causing a re-render. Useful for reading state inside callbacks without adding it as a dependency.
[3]StateHistoryControls<T>The history controls object. See {@link StateHistoryControls}.

Released under the MIT License.