You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A pragmatic, battle-tested checklist for reviewing React codebases (React 19+, Hooks era, Next.js-aware). Use it as a scan-during-PR reference — not a rulebook. Context always wins.
1. Project Setup
README.md present: Setup, scripts, env vars, architecture diagram. A new dev should be productive in <30 min.
.gitignore: Excludes node_modules/, .env*, dist/, build/, .DS_Store, coverage/, IDE folders.
package.json hygiene: Pinned or caret-versioned deps, no unused packages, engines field set, scripts documented.
Lockfile committed: package-lock.json / pnpm-lock.yaml / yarn.lock — never both.
ESLint + Prettier configured: Shared config (e.g., eslint-config-airbnb, @typescript-eslint), react-hooks/exhaustive-deps rule on, Prettier runs on pre-commit (Husky + lint-staged).
TypeScript: strict: true in tsconfig.json — non-negotiable for new projects.
Node version pinned: .nvmrc or volta config to avoid "works on my machine".
Aspect
✅ Good
❌ Bad
Dependencies
Lean, audited, no duplicates
200+ deps, unused libs, security warnings
Scripts
dev, build, test, lint, typecheck
Only start
2. Code Style & Readability
Naming: camelCase for variables/functions, PascalCase for components, UPPER_SNAKE for constants, useXxx for hooks. Boolean prefixes: is, has, should.
No var, no console.log left in committed code. Use const by default, let when reassigning. Strip logs via ESLint no-console.
Rules of Hooks: Call only at the top level, only in components or custom hooks. No conditionals, loops, or nested functions.
Exhaustive deps: Every reactive value used inside useEffect/useMemo/useCallback must be in the dependency array. Don't suppress the lint rule — fix the design.
Custom hooks for reuse: Any logic used in 2+ components belongs in useSomething. Prefix with use.
Minimal state: Derive whenever possible — don't store what you can compute.
Lift state only as far as needed: Don't push state to the root "just in case".
React 19 awareness: Use useActionState, useOptimistic, useFormStatus, and the new use() hook where appropriate. The compiler (React Compiler) may make manual memoization redundant — review accordingly.
useMemo / useCallback / React.memo: Apply where profiling shows benefit — not by default. With React Compiler, manual memoization is often unnecessary.
Next.js specifics: Correct use of Server vs Client Components ('use client' only where needed), next/image, next/font, route segment config, streaming with Suspense.
CI/CD: Lint, typecheck, test, build all pass before merge.
13. Best Practices & Final Polish
DRY: Extract repeated logic to utils/hooks — but don't over-abstract. Rule of three: duplicate twice, abstract on the third.
TypeScript: Strict mode, no any (use unknown + narrowing), shared types in a types/ folder.
File structure: Feature-based (features/auth/) scales better than type-based (components/, hooks/) for large apps.
Consistent formatting: Prettier + ESLint must pass in CI.
Accessibility, performance, and tests are not "later" — they're part of "done".
Commits & PRs: Conventional commits, small PRs (<400 lines), clear descriptions, screenshots for UI changes.
Document the gotchas: If something is non-obvious, a comment or ADR saves the next developer.
Usage: Print/Pin this checklist for every PR review.