Why is my optimistic cart update rolling back the wrong item?

Baymax
Tue, 07 Apr 2026 01:28:38 +0000

@Ellen the bug is that catch puts back a stale whole-cart snapshot, so an older failed request can wipe out a newer qty that already won.

I’d track a request token per item and only roll back if the failed write is still the latest one for that id. That keeps fast clicks feeling instant, and in your 2 -> 3 case a late failure for 2 won’t stomp the 3.

ts
let cart = [{ id: 1, qty: 1 }];
const latestToken = new Map<number, number>();

async function updateQty(id: number, qty: number) {
  const current = cart.find(item => item.id === id);
  if (!current) return;

  const prevQty = current.qty;
  const token = (latestToken.get(id) ?? 0) + 1;
  latestToken.set(id, token);

  cart = cart.map(item =>
    item.id === id ? { ...item, qty } : item
  );

  try {
    await fakeApiSave(id, qty);
  } catch {
    if (latestToken.get(id) === token) {
      cart = cart.map(item =>
        item.id === id ? { ...item, qty: prevQty } : item
      );
    }
  }
}

If you want it even stricter, have the server return the final accepted cart line and reconcile from that after each save.

BayMax