Review checklist
This is the checklist to run down — by eye, on any diff, yours or an AI’s — after the tools in Verification Tools have run and come back clean. It fits on one printed page on purpose: a checklist nobody actually opens during a review is worthless. Every line links to the lesson that explains why, so this page stays a list, not a re-run of the course. The groups follow the same order as How to read React you did not write.
flowchart LR H["Hooks and deps"] --> P["Partial tool coverage<br/>(eslint-plugin-react-hooks catches some; behavior needs a test)"] B["Boundary and directives"] --> M["Mostly human review<br/>(a real RSC framework build is the only real check)"] K["Keys and identity"] --> M S["State ownership"] --> P E["Effects vs events"] --> M C["Memo and compiler"] --> M
Hooks and their dependencies
Section titled “Hooks and their dependencies”- Does every
useEffect/useMemo/useCallbackdependency array include everything the callback actually reads? See useEffect & Effects. - Is a value that changes often (a callback, a theme) read through
useEffectEventrather than silently omitted from an effect’s deps? See the AI Bug Catalog, entry 2. - Is every hook called unconditionally, at the top level, in the same order every render — never after an early
return, never inside anif? See the AI Bug Catalog, entry 3. - Does
useRef<T>()always receive an explicit initial value (nullfor a DOM ref)? See TypeScript with React. - Does new code accept
refas a plain prop instead of wrapping itself inforwardRef? See useRef & the DOM. - Does every
useSyncExternalStore’sgetSnapshotreturn a primitive or a cached reference, never a fresh object/array literal? See External Stores. - Is every promise passed to
use()read from a stable cache, never built fresh inline in the render body? Seeuse()& Data Fetching. - Does the code import
useActionStatefromreact, notuseFormStatefromreact-dom? See the AI Bug Catalog, entry 8.
The server/client boundary and directives
Section titled “The server/client boundary and directives”- Does every file that calls a client-only hook (
useState,useEffect) or attaches an event handler actually have'use client'on itself or a parent, in a real RSC-capable project? See Server Components. - Does every prop crossing from a Server Component into a Client Component stay plain, serializable data (or a real Server Action) — never a bare function or class instance? See Server Components.
- Is
dangerouslySetInnerHTMLever fed user-supplied content without running it through a real sanitizer first? See the AI Bug Catalog, entry 11. - Is
useOptimistic’s setter (orrequestFormReset) called from insidestartTransition/an Action, never directly from a plain event handler? See Forms & useOptimistic.
Keys and identity
Section titled “Keys and identity”- Does every
.map()over a list use a stable id from the data askey— never the array index, and never omitted entirely? See the AI Bug Catalog, entries 13–14. - Does a
.map()that groups sibling elements use<Fragment key={...}>(imported explicitly), never the<>shorthand? See the AI Bug Catalog, entry 15. - Does an editor/detail component use
key={currentItemId}to force a clean reset when its subject changes, instead of accumulating stale internal state? See Rendering & Reconciliation.
Who owns each piece of state
Section titled “Who owns each piece of state”- Could this state be derived during render instead of synced from a prop with a
useEffect? See useEffect & Effects. - Is
setStateever called directly inside the render body, outside an event handler or effect? See the AI Bug Catalog, entry 17. - Is every object/array state update a genuinely new reference, never a
.push/direct-assignment mutation followed by calling the setter with the same reference? See State Snapshot & Purity. - Is a Context’s provider
valuememoized (useMemo), and does it carry only slow-changing, broadly-shared data — never a value that changes on every keystroke? See Context.
Effects vs events
Section titled “Effects vs events”- Does every
setcall after anawaitinsidestartTransition(async () => {...})sit inside its own nestedstartTransition? See Transitions. - Does a data fetch inside an effect cancel its previous in-flight request (
AbortController) when its identifier changes quickly? See useEffect & Effects. - Is any
Date.now()/Math.random()read during render, in code that will ever hydrate — instead of only inside an effect or passed down as a fixed prop? See the AI Bug Catalog, entry 22. - Does a
useLayoutEffectread a value only a siblinguseEffectwrites, expecting to see the current commit’s write instead of the previous one? See Commit Phase & Effects.
Memo pairing and compiler assumptions
Section titled “Memo pairing and compiler assumptions”- Does every prop passed to a
memo-wrapped component stay a stable reference — no inline object/array/function literal built at the call site? See Memoization & the Compiler. - If the project claims to run the React Compiler, is
babel-plugin-react-compileractually wired into the build — or does the code just assume auto-memoization that isn’t running? See The React Compiler. - Does a component’s return type annotated
JSX.Element/ReactElementever need to returnnull? Should it beReactNodeinstead? See TypeScript with React.