— The stack

Optimistic meal deletion: distinguish a rollback from a user-facing undo

Separate failed meal-delete rollback from user-facing Undo and preserve newer cache changes during concurrent mutations.

4 min readUpdated 2026-11-05By AptixLabs studio
Delete request: Optimistic removal pending; Failure: rollback: Reconcile without losing newer edits; Success: deleted: Authoritative removal accepted; Undo: restore: Separate supported server actionAptixLabs · 2026-11-05

Original explanatory diagram using synthetic or proposed states; not a product screenshot. View full-size diagram

An optimistic-delete rollback and a user-facing Undo button solve different problems. Rollback restores consistency when the server rejects a delete. Undo reverses an action the server may already have accepted. Design their identities, timing and dependent totals separately before using one cache snapshot for both.

Start with an account-and-day-scoped meal list, stable meal IDs and an authoritative delete response. Inventory derived daily totals and any child records. A deletion that disappears from one list but remains in the daily summary has not completed the visible data transition.

Snapshot the operation, not every future change

TanStack Query documents cancelling relevant queries, taking a snapshot, applying an optimistic update and reconciling after success or failure. The pattern needs adaptation when mutations overlap: restoring an old whole-list snapshot can erase changes accepted after that snapshot was taken.

TanStack Query: optimistic updates and rollback patterns

Executed isolated cache sequence
StepVisible IDsConsequence
Initial snapshotA, BDelete A begins
Optimistic removalBRequest pending
Another meal is addedB, CNewer change must survive
Whole snapshot rollbackA, BIncorrectly loses C
Targeted illustrative restorationA, B, CRetains the later addition

The fixture is a pure-array demonstration, not a mounted React Query test. Its targeted restoration shows the intended result for this simple case. Real reconciliation must also consider a concurrent correction or successful deletion of A, server ordering and the accepted version of each record. Blindly inserting a stale copy can be wrong too.

Use the authoritative result to finish reconciliation

The reviewed UltraFit360 delete hook cancels a scoped query, snapshots the list, filters the meal and restores the previous list on error. That source establishes a rollback pattern, not an implemented Undo feature. The overlapping-add fixture identifies a scenario worth testing against the full mutation lifecycle.

A refetch can be the simplest way to reconcile complex overlapping edits after settling. If the server returns enough authoritative data, a targeted update may be appropriate. Keep pending operation IDs so a failure callback from an earlier request cannot reverse a newer accepted action. Show a recoverable error without pretending the deleted meal was durably removed.

Give Undo a separate server contract

A proposed Undo could use a reversible tombstone with a restoration window, or another explicit restore operation. Define who can restore, which children return, how totals are rebuilt and what happens after the window closes. If deletion is permanent, a client-only button cannot honestly promise to recover the original record and its relationships.

Proposed action states:
visible → delete_pending → deleted
delete_pending → visible_on_failure
deleted → restore_pending → restored  // separate Undo contract

These states are illustrative and do not describe a current backend API. Keep a failed delete message distinct from “Undo successful.” A user should not need to infer whether the server ever accepted the action from a toast that disappears after a few seconds.

Test list state and totals together

Acceptance should cover a delete failure after an add, two deletions settling in reverse order, a refreshed list arriving mid-mutation and an account switch before the response. Verify that each rollback applies only to its originating account and reporting date. Reconcile daily nutrients and any cached preview from the same accepted state.

For a real Undo design, add expired restoration, repeated restore requests and a record changed by another authorized actor. Keep the isolated fixture’s claims narrow: it demonstrates why a whole snapshot can lose newer state, while the production solution still needs testing with the actual cache, API and persistence rules.

Ordering is another part of restoration. In the simple fixture A returns before B and C, but a real list may sort by meal time, creation time or a server sequence. Restore according to that rule rather than whichever array position the rollback happened to capture. Keep any pending addition visible until its own outcome is known. Test totals and ordering together so a correctly restored ID does not appear under the wrong meal group or reporting date.

Realtime sync firestore

React native 60fps

Bring the supported devices, installed SDK versions and a reproducible lifecycle or UI failure to scope a mobile engineering assessment.

Explore react native development

Is an optimistic-delete rollback the same as Undo?

No. Rollback reconciles a failed delete. Undo reverses an accepted user action and needs its own server-side identity and restoration policy.

Can an Undo button restore a permanently deleted record from cache?

It cannot reliably restore the original server record and relationships without a supported restoration or recreation contract.

Need help with react native app development?

Tell us about your product, existing stack and the problem you need to solve. We can discuss integration scope, implementation tradeoffs and a practical first milestone.

Start a conversation