| name | react-best-practices |
| description | React 19 performance and composition patterns for this Next.js landing page. Use when building components, hooks, or optimizing rendering. |
React 19 Best Practices
Component Patterns
Function declarations over arrow exports for components
export function HeroView({ data }: HeroViewProps) {
return <section>...</section>;
}
No forwardRef in React 19
ref is a regular prop — no wrapper needed:
export function Button({ className, ref, ...props }: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) {
return <button ref={ref} className={className} {...props} />;
}
Props: interfaces over types for components
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
isLoading?: boolean;
}
Never use any
Every prop, parameter, and return type must be explicitly typed. Use unknown + type narrowing if the type is truly dynamic.
Composition Over Configuration
- Prefer compound components over boolean prop explosion
- Use
children and slots over render props when possible
- Compose small, focused components rather than large monoliths
- Each component has a single responsibility
Bad: prop explosion
<Card showHeader showFooter headerTitle="X" footerAction={fn} bordered rounded />
Good: compound composition
<Card>
<CardHeader><CardTitle>X</CardTitle></CardHeader>
<CardContent>...</CardContent>
<CardFooter><Button onClick={fn}>Save</Button></CardFooter>
</Card>
Performance Rules
Avoid unnecessary re-renders
- Never define components inside other components
- Never create objects/arrays inline in JSX props
- Extract static data outside the component
- Use
useMemo only when profiling shows a bottleneck
Event handlers
- Define handlers outside JSX:
const handleClick = () => {} then onClick={handleClick}
- For parameterized handlers, use
useCallback only if passed to memoized children
Keys
- Never use array index as key for dynamic lists
- Use stable, unique identifiers
Hooks Rules
- Only call hooks at the top level (never inside conditions/loops)
- Custom hooks must start with
use
- Keep hooks focused — one concern per hook
- Extract shared logic into custom hooks when used in 2+ components
Client vs Server Components
- Default to Server Components (no
"use client")
- Add
"use client" only for: event handlers, browser APIs, state, effects, Framer Motion
- Never import server-only modules in client components
- Pass serializable props across the server/client boundary
Accessibility in Components
- Use semantic HTML elements (
button not div onClick)
- All interactive elements must be keyboard accessible
- Add
aria-label when visual label is absent
- Buttons must have
type="button" or type="submit" explicitly
- Images must have
alt text (empty alt="" for decorative)
File Organization
- One exported component per file
- Barrel exports (
index.ts) for public APIs
- Co-locate styles, types, and data with their component
- Keep component files under 150 lines — split if larger
Testing-Ready Patterns
- Components are pure functions of props (easy to test)
- Hooks are decoupled from UI (testable independently)
- Data layer is separate from presentation (mockable)