The React Component Evolution
React components have two syntaxes: class components (class MyComponent extends React.Component) and functional components (function MyComponent() or const MyComponent = () => {}). Class components: were the only way to have state and lifecycle methods before React 16.8 (2019). Functional components with hooks: became the standard after React 16.8. In 2026: virtually all new React code is written as functional components. Class components exist in legacy codebases.
The AI rule is simple: generate functional components for all new code. The complexity: many codebases have a mix of both. The AI must understand both patterns to: read and modify existing class components, convert class components to functional when asked, and avoid generating class syntax in a hooks-based codebase (or hooks in a class-based codebase when maintaining consistency is more important).
Why this matters for AI: the component pattern affects every piece of generated React code. State management (this.setState vs useState), side effects (componentDidMount vs useEffect), refs (createRef vs useRef), context (static contextType vs useContext). The AI generating the wrong pattern for the codebase: produces code that works but looks alien to the team.
Class Components: Legacy Pattern AI Rules
Class component anatomy: class UserProfile extends React.Component<Props, State> with constructor (initialize state), lifecycle methods (componentDidMount for data fetching, componentDidUpdate for responding to prop changes, componentWillUnmount for cleanup), and render() method returning JSX. AI rule for existing class components: 'Modify class components in-place. Use this.setState for state updates. Use lifecycle methods for side effects. Do not mix hooks into class components — hooks cannot be used in class components.'
Error boundaries: the one case where class components are still required. Error boundaries use componentDidCatch and getDerivedStateFromError — there is no hook equivalent. AI rule: 'Error boundary components must be class components. Use react-error-boundary library for a functional wrapper around the class pattern. All other components: functional.'
Class component anti-patterns the AI should avoid: binding methods in render (use class fields instead), derived state from props in componentDidUpdate (use useMemo in functional components), deep component hierarchies with prop drilling (use context or state management). When modifying class components: maintain the existing pattern unless specifically asked to refactor to functional.
React has no hook equivalent for componentDidCatch or getDerivedStateFromError. Error boundaries must be class components. The react-error-boundary package wraps this pattern in a reusable component so your team does not need to write class syntax. AI rule: import ErrorBoundary from react-error-boundary instead of writing a class component for error handling.
Functional Components: Modern Pattern AI Rules
Functional component anatomy: const UserProfile: React.FC<Props> = ({ name, email }) => { const [isEditing, setIsEditing] = useState(false); useEffect(() => { fetchUser(); }, []); return <div>...</div>; }. The component is a function. State is via hooks. Side effects are via useEffect. No this keyword, no lifecycle methods, no render method.
Hook rules the AI must follow: hooks must be called at the top level (never inside conditions, loops, or nested functions). hooks must be called in the same order every render. Custom hooks must start with 'use' prefix. AI rule: 'Never generate useState or useEffect inside an if block. Never generate hooks after an early return. The hook call order must be deterministic.'
Common patterns: useState for local state, useEffect for side effects and data fetching, useRef for DOM references and mutable values, useMemo for expensive computations, useCallback for stable function references (passed to child components), useContext for consuming context values. AI rule: 'Use the minimal set of hooks needed. Do not add useMemo or useCallback unless there is a performance reason (child component memoization, expensive computation).'
The most common AI mistake with functional components: generating useState or useEffect inside a conditional block. React tracks hooks by call order — if a hook is skipped on some renders, the order shifts and every subsequent hook reads the wrong state. The fix: always call hooks unconditionally at the top of the component, then use the values conditionally in the JSX or logic below.
Handling Mixed Codebases
Detection: the AI should scan existing components to determine the dominant pattern. If 80%+ are functional: generate functional components. If the codebase is heavily class-based (legacy project): match the existing pattern unless instructed to modernize. If mixed: generate functional for new files, maintain class pattern when editing existing class components.
Gradual migration strategy: when converting class to functional, do it one component at a time. Convert the component, update its tests, verify it works. Do not convert multiple components in one pass — each conversion can surface subtle behavioral differences (useEffect cleanup timing vs componentWillUnmount, useState batching vs this.setState batching). AI rule: 'Convert one component at a time. Test after each conversion. Preserve the component API (same props interface) during conversion.'
The 2026 reality: most active codebases have completed the migration to functional components. Class components survive in: enterprise codebases with strict change policies, libraries that support older React versions, and error boundary components. For the AI: functional components are the default. Class components are the exception that requires explicit detection.
Class-to-functional migration is safe when done incrementally. Convert one component, run its tests, verify the behavior. Why not batch? useEffect timing differs from componentDidMount (it fires after paint, not before). setState batching works differently in functional components. These subtle differences can cause flickering, stale closures, or race conditions that are hard to trace when multiple components change at once.
Component Pattern Summary
Summary of class vs functional component AI rules for React code generation.
- New code: always functional components with hooks. No exceptions except error boundaries
- Class components: this.state, lifecycle methods, render(). Legacy pattern — modify in-place
- Hooks: useState, useEffect, useRef, useMemo, useCallback, useContext. Top-level only
- Error boundaries: the only remaining use case for class components. Use react-error-boundary
- Mixed codebases: functional for new files, maintain class in existing class files
- Migration: one component at a time, preserve props interface, test after each conversion
- Detection: scan existing components. 80%+ functional = generate functional. Match the codebase
- 2026 default: functional components. The AI should never generate class components for new code