Build a social feed component with Like and Bookmark buttons that toggle instantly using optimistic state. Simulate a 20% server failure rate. Any failed mutation must roll back and show a toast notification. Rapid successive clicks must be debounced to prevent conflicting in-flight requests. The last confirmed server state must persist to localStorage so it survives page reloads.
Use a useRef boolean flag (inFlight.current) as the debounce guard rather than a setTimeout-based debounce — it is simpler and avoids stale closure issues inside the async handler.
For localStorage persistence, write to localStorage inside the try block after the API call resolves, not inside the optimistic update — this ensures only confirmed state is persisted.
Store both Like and Bookmark state in a single useState object ({ liked, bookmarked, likeCount }) to guarantee the rollback restores all three values atomically.
// Console log sequence for a successful like:
// t=0ms [click] optimistic: liked=true, count=43
// t=512ms [api] confirmed: liked=true, count=43
// t=512ms [storage] wrote { liked: true, likeCount: 43 }
// Console log sequence for a failed bookmark:
// t=0ms [click] optimistic: bookmarked=true
// t=501ms [api] error: Server error
// t=501ms [rollback] bookmarked=false
// t=501ms [toast] "Couldn't save bookmark"
Add undo via AbortController: show a 3-second "Undo" snackbar after a successful like, and cancel the in-flight request (or fire a DELETE) if the user clicks it.
Implement a retry queue: on network failure (as opposed to server 4xx), automatically retry the mutation up to 3 times with exponential backoff before rolling back.
Add an optimistic like-count tooltip that shows "+1 pending" while the mutation is in flight and disappears when confirmed.