Memento Usage
MementoBaseCaretaker
MementoBaseCaretaker is a service class that should receive a Disposable owner via dependency injection, not implement Disposable. The owner is responsible for cleanup of subscriptions.
Class Definition
class MementoBaseCaretaker<
TMemento,
Originator extends MementoBaseOriginator<TMemento>
> {
constructor(
owner: Disposable,
originator: Originator,
history: StatePort<TMemento[]>,
historyPointer: StatePort<number>
);
saveState(): void;
undo(): void;
redo(): void;
get history(): StatePort<TMemento[]>;
get historyPointer(): StatePort<number>;
get canUndo(): ComputedValue<boolean>;
get canRedo(): ComputedValue<boolean>;
}
Usage Example
In a React Component
import { useCreateStatePort, useViewModel } from '@xndrjs/adapter-react';
import { ViewModel, type StatePort, type Disposable } from '@xndrjs/core';
import { MementoBaseCaretaker } from '@xndrjs/memento';
import type { MementoBaseOriginator } from '@xndrjs/memento';
// Define your originator
class TodoListOriginator implements MementoBaseOriginator<Todo[]> {
constructor(private todosPort: StatePort<Todo[]>) {}
getMemento(): Todo[] | null {
return this.todosPort.get();
}
restoreMemento(memento: Todo[]): void {
this.todosPort.set(memento);
}
}
// Create a ViewModel wrapper
class TodoListViewModel extends ViewModel {
readonly caretaker: MementoBaseCaretaker<Todo[], TodoListOriginator>;
constructor(
todosPort: StatePort<Todo[]>,
historyPort: StatePort<Todo[][]>,
historyPointerPort: StatePort<number>
) {
super();
const originator = new TodoListOriginator(todosPort);
this.caretaker = new MementoBaseCaretaker(
this, // Pass this as owner
originator,
historyPort,
historyPointerPort
);
}
}
// Use in component
function TodoList() {
const todosPort = useCreateStatePort<Todo[]>([]);
const historyPort = useCreateStatePort<Todo[][]>([]);
const historyPointerPort = useCreateStatePort<number>(0);
const vm = useViewModel(
() => new TodoListViewModel(todosPort, historyPort, historyPointerPort)
);
const caretaker = vm.caretaker;
// Use caretaker methods
const canUndo = useReactiveValue(caretaker.canUndo);
const canRedo = useReactiveValue(caretaker.canRedo);
return (
<div>
<button onClick={() => caretaker.undo()} disabled={!canUndo}>
Undo
</button>
<button onClick={() => caretaker.redo()} disabled={!canRedo}>
Redo
</button>
</div>
);
}
Key Points
MementoBaseCaretakeris a service, not a ViewModel- It receives a
Disposableowner via dependency injection - Wrap it in a
ViewModelin your component for automatic lifecycle management - Use the owner for
.for(owner)when creating computed values