glimfly
code updated

Why does my like button flip back after I tap it?

In one sentence:Optimistic UI is a pattern where the screen updates instantly as if an action already succeeded, then quietly reverts if the server request behind it actually fails.

What it actually is

Optimistic UI updates your screen the instant you act, before your server has said yes. You tap “like,” the heart fills red immediately, and only afterward does a request actually reach your backend to save that like. If the request succeeds, nothing more happens, the screen already showed the right thing. If it fails, the interface reverts to whatever was last confirmed, which is the moment you see the flip-back.

Picture ordering through a food delivery app. The moment you tap “place order,” the app shows “Order confirmed” and starts a prep-time countdown, before the restaurant’s own system has actually accepted anything. Most of the time the restaurant does accept, so nothing more happens after that. Once in a while the restaurant is out of an ingredient or already closed, and the order gets cancelled after the fact, undoing what the app just told you. Optimistic UI works the same way: it shows success before it’s certain, then corrects itself the rare time it turns out to be wrong.

This is different from the underlying state simply being wrong. The optimistic version and the confirmed version are two separate values sitting side by side; the interface just shows you the optimistic one until the real one arrives.

Why your AI just did this

Waiting for a round trip to an API endpoint on every tap feels slow, so agents reach for optimistic updates to make apps feel instant. React has a hook built for exactly this, useOptimistic, which takes your current state and a value to display right away, then automatically falls back to the real state if the surrounding action fails. Data-fetching libraries like TanStack Query offer a similar pattern for mutations: you can update the cached data directly in an onMutate handler before the server responds, and roll it back in onError if the request comes back with a problem.

Lovable, Cursor, and Claude Code all reach for this pattern on anything with a fast, frequent interaction, like buttons, follow buttons, cart quantities, drag-to-reorder lists. It’s the same instinct behind debounce: both patterns exist so your interface doesn’t force you to watch every network round trip in real time.

When you’ll run into it

The classic case is exactly the one that started this: you tap like, it fills in, and a moment later it empties again with no message telling you why. The same thing happens with a follow button that un-follows itself, a cart quantity that resets to its old number, or a comment that appears in the list and then disappears.

Under the hood, something in the actual save failed: a dropped network connection, an expired login session, a server error, or a CRUD write rejected by a validation rule on the backend. The interface did exactly what it was built to do: show the optimistic version first, then reconcile with reality once the real response lands. What’s usually missing is any visible sign of why it reverted, so it reads as a bug instead of a failed save.

You’ll also meet the opposite problem: a flip-back on a request that actually succeeded. That’s a real bug, usually a mismatch between the optimistic state your agent guessed at and the shape of data the server actually sent back once it confirmed.

What to check

  • Open your browser’s Network tab, tap the button, and watch the actual request. If it returns an error status, the revert is correct behavior and the missing piece is user feedback, not the rollback itself
  • Ask your agent whether the failing action has an error handler at all, or whether it just silently falls back with nothing shown to you
  • If the button reverts even when the request succeeds, ask your agent to compare the optimistic value against the real server response. A shape mismatch there is the actual bug
  • Check for expired sessions or intermittent connectivity as the everyday cause behind occasional reverts, rather than assuming the whole feature is broken
  • Ask for a visible error message or toast on failure, so a failed save reads as “this didn’t save” instead of a mysterious flip

Say it like a dev

Instead of: “the like button flips back a second later” Say: “This looks like an optimistic update that’s rolling back silently on a failed request. Can you add an error message so a failed save is visible instead of just reverting?”

Instead of: “sometimes clicking things doesn’t stick” Say: “Is this using optimistic UI? If the request behind it fails, I want to see why, not just watch the state snap back.”

Instead of: “make it stop glitching” Say: “Check whether the optimistic state matches what the server actually returns on success. If they don’t match, that’s the bug, not the loading behavior.”

People actually ask

“Why did my like button undo itself a second after I tapped it?”

Your app is using optimistic UI: it filled in the heart the instant you tapped, assuming the request to your server would succeed, before that request actually finished. When the request comes back with an error (a dropped connection, an expired session, a failed database write), the interface reverts to the last confirmed state, which looks like your tap got undone. The tap itself worked fine; the save behind it didn't.

“What does 'optimistic update' actually mean?”

It means the interface shows the result you expect before the server has confirmed it happened. Instead of showing a spinner and waiting, the app assumes success, updates the screen right away, and only steps in to correct itself if the real response says otherwise. Most of the time nobody notices, because most requests succeed.

“How do I stop optimistic updates from silently reverting with no explanation?”

The revert itself is correct behavior when a request fails; what's usually missing is feedback. Ask your agent to add an error message or toast alongside the rollback, so a failed save looks like a failure instead of a glitch. If the flip-back happens even when the request succeeds, that's a separate bug: the optimistic state and the real server response don't match.

Related terms

Checked against

free tool · no signup

Just met this in a real session? Glim reads it in plain words.

Paste what your agent just did, a git diff, your terminal, or its summary, and Glim tells you what changed and what to check before you ship. Nothing stored.

Explain my session →