useUpdateFragment currently fires and forgets — once you update a fragment, there's no way to walk it back without manually dispatching the previous state. This makes optimistic UI patterns tedious.
Proposed API
update() returns a chainable object with the fragment bound and an internal undo/redo stack:
const update = useUpdateFragment()
// Chain multiple updates
const cart = update(cartRef, (draft) => { draft.quantity = 5 })
.update((draft) => { draft.quantity = 10 })
.update((draft) => { draft.color = 'red' })
// Walk backward/forward
cart.undo() // back to q=10
cart.undo() // back to q=5
cart.redo() // forward to q=10
// Discard everything this chain did
cart.reset() // back to state before the chain started
Behavior
- The first call
update(ref, updater) binds the fragment and starts the chain
- Each method returns a new chain object with the stack curried in
- Every
update, undo, redo, and reset dispatches updateFragment immediately
undo() at the bottom of the stack is a no-op (no dispatch)
redo() at the top of the stack is a no-op (no dispatch)
update() after undo() clears the redo stack (standard undo/redo semantics)
reset() restores the state from before the chain started and clears the stack
Use case: optimistic UI
const update = useUpdateFragment()
const cart = update(cartRef, (draft) => { draft.items.push(item) })
try {
await remote('/cart', { method: 'POST', body: item })
} catch {
cart.reset()
}
Getting started
git checkout v2
cd superglue/superglue
npm install
npx vitest run spec/lib/useSetFragment.spec.jsx # existing tests
When opening your PR, target the v2 branch.
useUpdateFragmentcurrently fires and forgets — once you update a fragment, there's no way to walk it back without manually dispatching the previous state. This makes optimistic UI patterns tedious.Proposed API
update()returns a chainable object with the fragment bound and an internal undo/redo stack:Behavior
update(ref, updater)binds the fragment and starts the chainupdate,undo,redo, andresetdispatchesupdateFragmentimmediatelyundo()at the bottom of the stack is a no-op (no dispatch)redo()at the top of the stack is a no-op (no dispatch)update()afterundo()clears the redo stack (standard undo/redo semantics)reset()restores the state from before the chain started and clears the stackUse case: optimistic UI
Getting started
When opening your PR, target the
v2branch.