useDataHistory
A hook that automatically tracks changes to an Observable and manages undo/redo history. Records a snapshot automatically whenever the source Observable changes. Built on top of useManualHistory, with additional support for auto-commit, pause/resume, and transaction.
Live editor
Tracking on
Every change commits immediately while tracking is active.
History timeline
Newest snapshot is pinned at the top.
#1
""
import { import useDataHistory
useDataHistory, import useObservable
useObservable } from "@usels/web";
function function Component(): JSX.Element
Component() { const const text$: any
text$ = import useObservable
useObservable("hello"); const { const undo: any
undo, const redo: any
redo, const canUndo$: any
canUndo$, const canRedo$: any
canRedo$ } = import useDataHistory
useDataHistory(const text$: any
text$);
return ( <JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> <JSX.IntrinsicElements.input: DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input InputHTMLAttributes<HTMLInputElement>.value?: string | number | {} | undefined
value={const text$: any
text$.any
get()} InputHTMLAttributes<HTMLInputElement>.onChange?: ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(e: ChangeEvent<HTMLInputElement, HTMLInputElement>
e) => const text$: any
text$.any
set(e: ChangeEvent<HTMLInputElement, HTMLInputElement>
e.ChangeEvent<HTMLInputElement, HTMLInputElement>.target: EventTarget & HTMLInputElement
target.any
value)} /> <JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick={const undo: any
undo} ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
disabled={!const canUndo$: any
canUndo$.any
get()}>Undo</JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> <JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick={const redo: any
redo} ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
disabled={!const canRedo$: any
canRedo$.any
get()}>Redo</JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> );}import { createDataHistory, observable } from "@usels/web";
function Component() { "use scope" const text$ = observable("hello"); const { undo, redo, canUndo$, canRedo$ } = createDataHistory(text$);
return ( <div> <input value={text$.get()} onChange={(e) => text$.set(e.target.value)} /> <button onClick={undo} disabled={!canUndo$.get()}>Undo</button> <button onClick={redo} disabled={!canRedo$.get()}>Redo</button> </div> );}pause / resume — stop and restart auto-tracking
Section titled “pause / resume — stop and restart auto-tracking”import { useDataHistory, useObservable } from "@usels/web";
function Component() { const text$ = useObservable("hello"); const { pause, resume, isTracking$ } = useDataHistory(text$);}import { createDataHistory, observable } from "@usels/web";
function Component() { "use scope" const text$ = observable("hello"); const { pause, resume, isTracking$ } = createDataHistory(text$);}transaction — group mutations into one record
Section titled “transaction — group mutations into one record”Multiple changes inside transaction() are recorded as a single undo step.
Call the provided cancel() to abort the commit entirely.
import { useDataHistory, useObservable } from "@usels/web";
function Component() { const value$ = useObservable(0); const { transaction, undo } = useDataHistory(value$);}import { createDataHistory, observable } from "@usels/web";
function Component() { "use scope" const value$ = observable(0); const { transaction, undo } = createDataHistory(value$);}shouldCommit — conditional auto-commit
Section titled “shouldCommit — conditional auto-commit”Return false from shouldCommit to skip recording specific values.
import { useDataHistory, useObservable } from "@usels/web";
function Component() { const count$ = useObservable(0); // Only record even numbers const { undo } = useDataHistory(count$, { shouldCommit: (value) => value % 2 === 0, });}import { createDataHistory, observable } from "@usels/web";
function Component() { "use scope" const count$ = observable(0); const { undo } = createDataHistory(count$, { shouldCommit: (value) => value % 2 === 0, });}capacity — limit undo depth
Section titled “capacity — limit undo depth”import { useDataHistory, useObservable } from "@usels/web";
function Component() { const text$ = useObservable(""); // Keep at most 50 undo steps const { undo, redo } = useDataHistory(text$, { capacity: 50 });}import { createDataHistory, observable } from "@usels/web";
function Component() { "use scope" const text$ = observable(""); const { undo, redo } = createDataHistory(text$, { capacity: 50 });}Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
source$ | Observable<Raw> | - The Observable to track. |
options | DataHistoryOptions<Raw, Serialized> (optional) | - Configuration for auto-tracking, filtering, and serialization. |
DataHistoryOptions
Section titled “DataHistoryOptions”Returns
Section titled “Returns”DataHistoryReturn<Raw, Serialized>
| Name | Type | Description |
|---|---|---|
isTracking$ | ReadonlyObservable<boolean> | Whether auto-tracking is currently active. |
pause | Fn | Stop auto-committing. |
resume | (commitCurrent?: boolean | undefined) => void | Restart auto-committing. If commitCurrent is true, immediately commit current value. |
transaction | (fn: (cancel: Fn) => void) => void | Group multiple mutations into a single history record. Call cancel() inside fn to abort. |
canUndo$ | ReadonlyObservable<boolean> | Whether undo is possible (undoStack is non-empty). |
canRedo$ | ReadonlyObservable<boolean> | Whether redo is possible (redoStack is non-empty). |
history$ | ReadonlyObservable<UseHistoryRecord<Serialized>[]> | Full history array, newest first: [current, previous, ...]. |
last$ | ReadonlyObservable<UseHistoryRecord<Serialized>> | The most recent (current) history record. |
commit | Fn | Record the current source value as a new history point. Clears redo stack. |
undo | Fn | Restore the previous committed value. |
redo | Fn | Re-apply the next value after an undo. |
clear | Fn | Wipe all history and create a fresh initial record from current source. |
reset | Fn | Restore source to the last committed value without modifying stacks. |