Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
The core optimistic UI pattern is always three steps: update local state immediately so the user sees the change at zero latency, fire the async mutation in the background, and revert local state if the mutation fails. This three-step contract is so reliable and repeatable that every major UI library — React Query, SWR, Apollo, Zustand — has first-class support for it. Understanding the raw useState version first gives you the mental model to use those abstractions correctly and to debug them when they go wrong. The revert step is the part most developers initially skip, and it is the part that matters most when a real failure occurs.
A Like button that toggles instantly via useState, fires a fetch in the background, and reverts with an error message if the server rejects the mutation. Both the optimistic path and the rollback path are visible.
0.2 to 0.8 and click the button rapidly — observe how the rollback correctly restores liked to whatever previous was captured as at the time of each click.setError(null) call to after the setLiked(!previous) line and verify the error message clears before the new request resolves, not after.42 → 43 optimistically) and verify the rollback restores the exact pre-click count even after multiple fast clicks.console.log('rollback to', previous) inside the catch block and confirm in the console that the logged value matches the button's displayed state after each failed click.import { useState } from "react";
async function fakeLikeAPI(liked: boolean): Promise<void> {
await new Promise((r) => setTimeout(r, 600));
if (Math.random() < 0.2) throw new Error("Server error");
}
export function LikeButton() {
const [liked, setLiked] = useState(false);
const [error, setError] = useState<string | null>(null);
async function handleLike() {
const previous = liked;
setError(null);
setLiked(!previous); // step 1: optimistic update
try {
await fakeLikeAPI(!previous); // step 2: async mutation
} catch (e) {
setLiked(previous); // step 3: rollback
setError("Could not save — please try again.");
}
}
return (
<div>
<button onClick={handleLike}>{liked ? "❤️ Liked" : "🤍 Like"}</button>
{error && <p style={{ color: "red" }}>{error}</p>}
</div>
);
}