Fix a React useState Stale-State Bug
A real fullstack problem you debug end to end in a live cloud workspace, then show on your portfolio. No tutorial, no toy app - a broken system that behaves like production.
The scenario
The app is a tiny React counter. Open it in your browser at the preview URL.
The broken code you start with
// all three calls capture the same stale `count`
onClick={() => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
}}What this teaches you
What you did: Switched the three setCount(count + 1) calls to setCount(c => c + 1). The first form is buggy ONLY when called multiple times in one handler - each call captures the same stale count from render and computes the same target value, so React batches them to a single update. The functional updater fixes this because React passes the latest pending state into each callback.
Why it matters: Single setState calls usually look fine - React re-renders between clicks, so count is fresh by the next handler. The bug shows up when you batch multiple updates: in one handler, in a loop, or in async callbacks. That's exactly when interview screens like to ask about it.
In the real world: This bites hardest in: - rapid successive clicks (typing in a search box, +1 buttons) - any effect / setTimeout that captures state - reducers - Redux/useReducer dispatch is also functional-update, same principle ESLint's react-hooks/exhaustive-deps rule catches many cases by flagging missing dependencies in useEffect. Make it strict in your team's lint config and 90% of stale-closure bugs surface at PR time.
What you'll practice
- Understanding why batched setState reads stale state
- Using the functional updater form of setState
- Verifying the counter increments correctly
Why this impresses a hiring manager
- This is a real fullstack problem teams hit in production - not a synthetic puzzle.
- It shows you can diagnose and fix a Fullstack issue in a live system end to end.
- It lands on your portfolio as a scenario a hiring manager can open and click through.
Switched the three setCount calls in addThree to the functional updater form - setCount(c => c + 1) - so each call sees the latest state instead of three stale captures of the same count, and the +3 button actually adds 3
Keep going
Build this project free
You're in a real cloud workspace in 30 seconds. Fix it, and it lands on your portfolio.
Start this project →