Skip to main content

React Code Review Checklist

Rapid-scan checklist for React web application code reviews. For React Native, see React Native Code Review Checklist.


Security Red Flags - Block PR Immediately

  • dangerouslySetInnerHTML without sanitization: HTML injection vulnerability → React Security Best Practices
  • API keys in source code: Exposed credentials in component files, constants, or environment files committed to repo
  • Credentials in localStorage: Tokens, passwords stored in localStorage instead of secure httpOnly cookies
  • eval() or Function() constructor: Code execution vulnerabilities
  • Unvalidated redirects: window.location or navigate() with user input without validation
  • XSS in user-generated content: Rendering user input without escaping (e.g., in innerHTML, dangerouslySetInnerHTML)
  • Exposed sensitive data in client state: PII, full credit card numbers, passwords in Redux/Zustand state
  • Missing CSRF protection: State-changing operations without CSRF tokens
  • Insecure dependencies: Known vulnerabilities in npm packages (check with npm audit)

Common Mistakes

Hooks Usage

  • Missing dependencies in useEffect/useCallback/useMemo dependency arrays → React General - Hooks
  • Stale closures capturing old state/props values
  • Calling hooks conditionally or inside loops (violates Rules of Hooks)
  • useState inside loops or conditional blocks
  • Not using useCallback for event handlers passed as props to memoized children
  • Forgetting cleanup functions in useEffect (subscriptions, timers, listeners)

Re-render Issues

  • Infinite re-render loops (state update triggering effect that updates state) → React Performance - Re-render Optimization
  • Creating new object/array literals in render ({}, []) passed as props
  • Defining components inside other components (causes remounting)
  • Anonymous functions as props without useCallback to memoized components

Component Design

  • Prop drilling through 3+ levels instead of context or composition → React General - Component Composition
  • Components larger than 200-300 lines (extract sub-components)
  • Business logic mixed with rendering logic (extract to custom hooks)
  • Using class components instead of functional components with hooks

State Management

  • Overusing global state (Zustand/Redux) for local UI state → React State Management
  • Mutating state directly instead of creating new objects/arrays
  • Not using immer or spread operators for nested state updates
  • Storing derived data in state instead of computing from existing state
  • Missing error state and loading state in async operations

TypeScript Issues

  • Using any type instead of proper types
  • Missing prop type definitions on components
  • Not typing event handlers (React.MouseEvent, React.ChangeEvent)
  • Inline type definitions instead of reusable interfaces/types

Watch For - Performance & Correctness Issues

Performance

  • Missing React.memo on expensive pure components → React Performance - Memoization
  • Missing useMemo for expensive calculations
  • Large component trees without code splitting (React.lazy, dynamic imports)
  • Unoptimized images (missing lazy loading, wrong formats, no responsive images)
  • Not virtualizing long lists (use react-window or react-virtual) → React Performance
  • Re-rendering entire lists when only one item changes (missing proper key prop)

Memory Leaks

  • Missing cleanup in useEffect for event listeners
  • Subscriptions not unsubscribed on unmount
  • Timers (setTimeout, setInterval) not cleared
  • Async operations updating state after component unmounts

Error Handling

  • Missing error boundaries around feature modules → React General - Error Boundaries
  • No error state in async data fetching
  • Unhandled promise rejections
  • Using console.error instead of proper error reporting service

Forms

  • Not using controlled components for form inputs → React Forms
  • Missing form validation before submission
  • No loading/disabled state during form submission
  • Storing sensitive form data in unencrypted state

Data Fetching

  • Fetching data in components instead of custom hooks or query library → React General - Data Fetching
  • Not handling loading and error states
  • No request deduplication for identical concurrent requests
  • Missing request cancellation on component unmount
  • Refetching data unnecessarily on every render

Best Practices - Code Quality

Component Structure

  • Functional components with TypeScript → React General
  • Props interface defined above component
  • Destructured props in function signature
  • Early returns for conditional rendering
  • Extract complex JSX into sub-components or variables
  • Use composition over prop drilling

Hooks Best Practices

  • Custom hooks for reusable stateful logic → React General - Custom Hooks
  • Prefix custom hooks with use (naming convention)
  • All dependencies included in hook dependency arrays
  • Cleanup functions for subscriptions, timers, listeners
  • useCallback for functions passed to memoized child components
  • useMemo for expensive computations

State Management

  • Local state (useState) for UI-only state → React State Management
  • Context for theme, user preferences, rarely-changing data
  • Zustand/Redux for complex shared state across features
  • React Query for server state (data fetching, caching)
  • Immutable state updates (spread operators or immer)

Performance

  • React.memo for expensive pure components → React Performance
  • Code splitting with React.lazy and Suspense
  • Lazy load images with loading="lazy"
  • Virtualized lists for 100+ items
  • Debounce/throttle expensive operations (search, scroll handlers)
  • Web Vitals monitoring (LCP, FID, CLS)

Testing

  • Unit tests for custom hooks and utility functions → React Testing
  • Integration tests for component interactions
  • Accessibility tests (axe, jest-axe)
  • Test user interactions, not implementation details
  • Mock external dependencies (API calls, timers)

Accessibility

  • Semantic HTML elements (<button>, <nav>, <main>)
  • ARIA labels where semantic HTML insufficient
  • Keyboard navigation support (focus management, tab order)
  • Color contrast meeting WCAG 2.1 AA standards (4.5:1 for text)
  • Focus indicators visible on interactive elements
  • Screen reader testing (NVDA, VoiceOver)

Quick Scan Table

CategoryWhat to CheckSeverityReference
SecurityNo dangerouslySetInnerHTML without sanitizationBlockSecurity
SecurityNo API keys in source codeBlockConfiguration
SecurityNo credentials in localStorageBlockSecurity
HooksDependencies complete in useEffect/useCallback/useMemoFixHooks
HooksCleanup functions for subscriptions/timersFixHooks
HooksNo hooks in conditionals/loopsBlockHooks
PerformanceNo infinite re-render loopsFixPerformance
PerformanceLong lists virtualizedFixPerformance
GOOD:PerformanceCode splitting for routesReview
StateNo direct state mutationFixState Management
GOOD:StateProper state location (local vs global)Review
TypeScriptNo any typesFixReact General
TypeScriptProps interfaces definedFixReact General
GOOD:AccessibilitySemantic HTML usedReview
AccessibilityKeyboard navigation worksFixAccessibility
Error HandlingError boundaries presentFixReact General
GOOD:TestingCritical paths testedReview

Legend:

  • Block PR - Security vulnerability or critical bug
  • Fix Before Merge - Performance issue, correctness problem, or likely bug
  • [GOOD] Review & Discuss - Code quality improvement

Additional Considerations

Component Anti-Patterns

  • God components (500+ lines, too many responsibilities)
  • Premature optimization (memoizing everything)
  • Overusing Context (causes unnecessary re-renders)
  • Not splitting code by route
  • Inconsistent file/folder naming
  • Missing TypeScript strict mode configuration

Styling Issues

  • Inline styles for static styles (use CSS modules or styled-components)
  • Hardcoded colors instead of theme variables
  • Missing responsive design (mobile, tablet, desktop)
  • No dark mode support when required
  • Accessibility issues (color contrast, focus indicators)

Build & Bundle

  • Bundle size over 500KB (before compression) for initial load
  • No tree shaking configured
  • Development dependencies in production bundle
  • Missing source maps for production debugging
  • No asset optimization (images, fonts)

Modern React Features

  • Not using React 18 concurrent features when beneficial (startTransition, useDeferredValue)
  • Missing Suspense boundaries for code splitting
  • Not leveraging server components (if using Next.js 13+)

Block Checklist - Must Fix Before Merge

  • No dangerouslySetInnerHTML without sanitization
  • No API keys or secrets in source code
  • No credentials in localStorage
  • Hooks not called conditionally or in loops
  • All useEffect dependencies included or intentionally omitted
  • Cleanup functions present for subscriptions/timers
  • No infinite re-render loops
  • No direct state mutation
  • TypeScript errors resolved (no @ts-ignore without explanation)
  • Error boundaries present for feature modules

React-Specific Guides:

Cross-Platform:

Process: