Use when: you want the UI to reflect a mutation immediately, before the server
confirms it — then reconcile or roll back when the response arrives.
Don’t use when: the action is destructive and hard to undo, or the server
response carries data that can’t be predicted client-side.
Apply the change to local state immediately, record enough context to roll back,
fire the request, and on failure restore the previous state (or re-fetch the
authoritative list).
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<
interface TodoState
TodoState> {
constructor() {
super({
TodoState.items: Todo[]
items: [],
TodoState.error: string |null
error: null });
}
TodoCubit.toggleDone: (id:string)=>Promise<void>
toggleDone=async(
id: string
id:string)=> {
// 1. Snapshot for rollback.
const
const previous:Todo[]
previous = this.
StructuralContainer<TodoState>.state: TodoState
state.
TodoState.items: Todo[]
items;
// 2. Apply optimistically — update only the matching item.
Override of StructuralContainer.patch that routes through the
StateContainer concerns: disposed guard, dev-only emit-rate check,
_changedWhileHydrating flag, pending-change capture (so stateChanged
system events see the merged prev/next), and the registry-level
stateChanged notification. We still call
super.patch so path-marking semantics (the whole point of patch) are
preserved.
patch({
items?: readonly {
id?: string |undefined;
text?: string |undefined;
done?: boolean |undefined;
}[] |undefined
items:
const previous:Todo[]
previous.
Array<Todo>.map<Todo>(callbackfn: (value:Todo, index:number, array:Todo[])=> Todo, thisArg?: any): Todo[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
@param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map((
t: Todo
t)=> (
t: Todo
t.
Todo.id: string
id===
id: string
id? { ...
t: Todo
t,
Todo.done: boolean
done: !
t: Todo
t.
Todo.done: boolean
done } :
t: Todo
t)),
error?: string |null|undefined
error: null,
});
try {
await
const api: {
markDone(id:string):Promise<void>;
}
api.
functionmarkDone(id:string):Promise<void>
markDone(
id: string
id);
// Server confirmed — nothing more to do.
} catch (
function(localvar)e: unknown
e) {
// 3. Roll back to the snapshot on failure.
// ⚠️ Do NOT ship the full state to an analytics sink before
// confirming — a rolled-back item would send false telemetry.
Override of StructuralContainer.patch that routes through the
StateContainer concerns: disposed guard, dev-only emit-rate check,
_changedWhileHydrating flag, pending-change capture (so stateChanged
system events see the merged prev/next), and the registry-level
stateChanged notification. We still call
super.patch so path-marking semantics (the whole point of patch) are
preserved.
patch({
items?: readonly {
id?: string |undefined;
text?: string |undefined;
done?: boolean |undefined;
}[] |undefined
items:
const previous:Todo[]
previous,
error?: string |null|undefined
error:
var String:StringConstructor
(value?:any)=> string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(
function(localvar)e: unknown
e) });
}
};
}
// Hoisted to module level so the reference is stable across renders.
// This component only calls actions and never reads state, so an empty