React Anti-Patterns · Code Review
Code that works, passes tests and looks clean — and is still wrong. Every lesson hands you a component to review: find the problems before the analysis, follow the execution sequence that causes them, and decide which would block the PR. Several lessons contain code that looks suspicious and is fine — flagging good code has a cost too.
This course reviews code. The model — render vs commit, state snapshots, effect lifecycle, identity, memoization — is taught in React Patterns, Good Practices & Internals. Every lesson here links the lesson there that it depends on.
Let’s figure it out.
Ask me about this course or where to start.
What causes a render, why render must stay pure, and why the state you just set is not the state you are holding.
- Step 1Correctness
What Actually Causes a Render?
The counter increments — a `console.log` proves the variable goes up — and the screen never changes. There is ...
Start Lesson - Step 2Correctness
Render Must Stay Pure
A component writes to `localStorage` and pushes to a module-level array while rendering. In production it work...
Start Lesson - Step 3Correctness
State Is a Snapshot
A handler calls `setCount(count + 1)` three times and the counter goes up by one. Then it logs `count` right a...
Start Lesson
Derived state, props copied into state, booleans that are really a state machine, state that is too high, state that is duplicated, and mutation.
- Step 4
Storing Derived State
Three pieces of state, and the third is the first two glued together by an effect. It works, and it renders tw...
Start Lesson - Step 5CorrectnessDepends
Duplicating Props Into State
A reviewer opens a PR. The component takes a `name` prop and copies it into state on the first line. Everythin...
Start Lesson - Step 6Correctness
Multiple Booleans for One State Machine
Three booleans describe one request. Three booleans have eight combinations; the request has four states....
Start Lesson - Step 7
State That Should Be Local
The app's root owns whether a tooltip is open. Every keystroke in the tooltip's search box re-renders the enti...
Start Lesson - Step 8Correctness
State That Should Be Shared
Two components each keep their own copy of the selected currency. They start equal, so it looks fine, and they...
Start Lesson - Step 9Correctness
Mutating State
Two handlers change the data correctly and neither one updates the screen. The console proves the objects chan...
Start Lesson
Effects that calculate, effects that respond to clicks, dependency lies, infinite loops, unstable dependencies, missing cleanup, and races.
- Step 10
Using Effects for Calculations
An effect filters a list into state whenever the list changes. It is correct, it is one of the most common sha...
Start Lesson - Step 11Correctness
Using Effects to Respond to User Events
Clicking *place order* sets a flag; an effect watches the flag and sends the order. It works, and it has a bug...
Start Lesson - Step 12Correctness
Effect Dependency Lies
The effect reads `userId` and declares `[]`. The lint rule was disabled with a comment explaining that it only...
Start Lesson - Step 13Correctness
Infinite Effect Loops
An effect sets state that its own dependency array depends on. The component renders forever, the fan spins up...
Start Lesson - Step 14Correctness
Objects and Functions as Effect Dependencies
The effect connects to a chat room and depends on an `options` object. The object is built during render, so i...
Start Lesson - Step 15Correctness
Missing Effect Cleanup
Three effects start something that outlives the render: a listener, an interval and a subscription. None of th...
Start Lesson - Step 16Correctness
Async Race Conditions
Click Alice, Bob, Charlie in quick succession. The requests return in a different order than you asked for the...
Start Lesson
Refs used as hidden state, refs used to dodge renders, and the DOM React thinks it owns — plus the cases where every one of those is correct.
- Step 17Correctness
Using a Ref as Hidden State
A form keeps its draft in a ref because "typing shouldn't re-render the whole thing". The input works — it is ...
Start Lesson - Step 18Depends
Wrapping State in a Ref to Avoid Re-renders
This component keeps the same value in both a state and a ref, and reads whichever is convenient. That pattern...
Start Lesson - Step 19CorrectnessDepends
Manipulating DOM That React Owns
A handler sets `textContent` and `style.color` directly on a node React rendered. It works — until the next re...
Start Lesson
The component that grew, the component that should not exist, prop drilling versus context abuse, the god provider, and hooks that only rename React.
- Step 20
The Giant Component
One component fetches, filters, sorts, renders a table, owns a modal, owns a form, checks permissions and fire...
Start Lesson - Step 21
Over-Componentization
Seven components render one line of text. Every one of them is a pure function that takes props and returns JS...
Start Lesson - Step 22Depends
Prop Drilling vs Context Abuse
A value is passed three levels down as a prop, and a reviewer has asked for it to be moved into context. Somet...
Start Lesson - Step 23
The Giant Context Provider
One provider holds the user, the theme, the cart, the filters and a modal flag. Typing in the filter box re-re...
Start Lesson - Step 24Depends
Premature Custom Hooks
Three custom hooks. One of them earns its name; the other two are React with a different spelling....
Start Lesson
Index keys, random keys, and using a key on purpose to reset a subtree — the same mechanism producing a bug, a disaster and a technique.
- Step 25CorrectnessDepends
Using the Array Index as a Key
QA reports: "deleting a task moves the checkbox ticks to the wrong tasks". The delete is correct. The state is...
Start Lesson - Step 26Correctness
Random Keys
A user reports: "I can't type in the search box — it loses focus after every letter." Someone had added `key={...
Start Lesson - Step 27Depends
Using a Key on Purpose to Reset State
Same mechanism as the last two lessons, used deliberately. Switching users should discard the half-typed draft...
Start Lesson
useMemo everywhere, useCallback everywhere, memo everywhere, what the React Compiler changes, and work that is expensive for reasons memoization cannot touch.
- Step 28
useMemo Everywhere
Six memos in one component. Five of them wrap arithmetic or string concatenation; one wraps a genuine O(n log ...
Start Lesson - Step 29Depends
useCallback Everywhere
Four callbacks, all wrapped. Two of them are handed to a `memo`-wrapped child or used as an effect dependency;...
Start Lesson - Step 30
React.memo Everywhere
Every component in this file is wrapped in `memo`. Click the counter and watch how many of them re-render anyw...
Start Lesson - Step 31Depends
React Compiler and Manual Memoization
"The compiler memoizes everything, so we can delete all of this." That sentence is half right, and the half th...
Start Lesson - Step 32
Expensive Work in Render
A component filters, sorts and maps a large dataset on every render — including every keystroke in an unrelate...
Start Lesson
State updates at pointer frequency, layout measured on every move, and fifty thousand DOM nodes — three costs that are not React's.
- Step 33Depends
State Updates in High-Frequency Pointer Events
A drag interaction stores the pointer position in state on every `pointermove`. It is the most obvious way to ...
Start Lesson - Step 34
Measuring Layout Repeatedly
A resize handle reads `getBoundingClientRect()` on every pointer move, and again inside a `useLayoutEffect` af...
Start Lesson - Step 35Depends
Rendering Huge Lists Without Virtualization
A list renders every row it has. With 20 rows that is correct and simple. With 5 000 it is 5 000 DOM nodes the...
Start Lesson
The loading boolean, server state modelled as client state, and the three outcomes nobody designs for.
- Step 36Correctness
Boolean Loading Everywhere
`isLoading` starts as one boolean and grows a second for errors, then a third for "has ever loaded". The compo...
Start Lesson - Step 37Correctness
Fetching Server Data Like Local State
Two components each fetch the same user on mount. The data is stored in `useState`, so nothing knows the other...
Start Lesson - Step 38Correctness
Ignoring Loading, Empty and Error UX
The component renders the success path. The other three outcomes are whatever happens to fall out: a flash of ...
Start Lesson
Controlled by default without asking why, effects wired between fields, and the one-object form state that re-renders everything.
- Step 39Depends
Making Everything Controlled Without a Reason
Twelve fields, twelve pieces of state, twelve `onChange` handlers. Every keystroke in any field re-renders the...
Start Lesson - Step 40Correctness
Synchronising Form State With Effects
Four effects wire fields to each other: quantity feeds subtotal, subtotal feeds tax, tax feeds total, and coun...
Start Lesson - Step 41CorrectnessDepends
The Giant Form State Object
One `useState` holds every field, and every change spreads the whole object. It is the most common form shape ...
Start Lesson
Reducers that mutate, reducers that copy what did not change, external stores read without subscribing, and everything in global state.
- Step 42Correctness
Incorrect useReducer Usage
The reducer pushes onto `state.items` and returns `state`. Dispatching does nothing visible — and then a later...
Start Lesson - Step 43
Reducers That Copy What Did Not Change
This reducer is scrupulously immutable — it rebuilds every nested object on every action, including the ones t...
Start Lesson - Step 44Correctness
External Stores Without Proper Subscription
A module-level store holds the cart. Components read `store.items` during render and call `store.add()` from h...
Start Lesson - Step 45Depends
Putting Everything in Global State
A store holds the signed-in user, the theme — and also whether a dropdown is open and what the user has typed ...
Start Lesson
Old habits that stopped being necessary, Actions, optimistic UI that can lose, Suspense as it actually works, and the server boundary.
- Step 46Depends
Old Patterns Used Automatically
Four habits from earlier React, all still working, all still being typed out of muscle memory. Two of them are...
Start Lesson - Step 47Correctness
Misunderstanding Actions
A form tracks `isPending` by hand, disables its own button, catches its own errors and resets its own fields. ...
Start Lesson - Step 48Correctness
Incorrect Optimistic UI
The like button updates instantly and never takes it back. Fail the request and the count stays wrong until a ...
Start Lesson - Step 49CorrectnessDepends
Suspense as a Loading Spinner Wrapper
A component wraps a child in `<Suspense>` and expects React to wait for the `fetch` inside it. React does not,...
Start Lesson - Step 50Depends
Server vs Client Responsibility
This lesson is framework-specific and does not run here: React Server Components need a bundler and a server b...
Start Lesson
Five components with several independent problems each. Find them before the analysis — and in Lab 3, be right about the two that are fine.
- Step 51Correctness
Lab 1 — User Search
A search box that queries an API as you type. It shipped, and it mostly works — which is exactly the kind of c...
Start Lesson - Step 52Correctness
Lab 2 — Shopping Cart
A cart that adds items, changes quantities and shows a total. The bug report says: “sometimes the quantity doe...
Start Lesson - Step 53Depends
Lab 3 — Dashboard, and the Code That Only Looks Wrong
Three of the things in this component are worth a PR comment. Two of them are fine, and one of those two is th...
Start Lesson - Step 54
Lab 4 — Drag-and-Drop Board
A board with draggable cards. It is smooth with three cards and visibly stutters with sixty, on a machine that...
Start Lesson - Step 55Correctness
Lab 5 — Async Form
A form that submits a comment. It has a loading boolean, an effect that fires the request, and optimistic UI t...
Start Lesson
One feature, twelve things worth an opinion, nine of which are problems. Write the review before you write any code.
The rules by category and the four decision trees, written to be re-opened during a review rather than memorised once.
- Step 57Depends
Reference — The Rules, by Category
Eleven categories, each with the question to ask rather than the rule to obey. Written to be re-read during a ...
Start Lesson - Step 58Depends
Reference — The Four Decision Trees
Four questions, asked in order, decide most of what this course covers. They are printed below, and then you r...
Start Lesson