React Patterns
Modern React and Next.js patterns with TypeScript.
Framework Selection
| Setup | Best For | Use When |
|---|
| Next.js App Router | Full-stack, SSR/SSG | SEO matters, need server components |
| Next.js Pages Router | Simpler SSR | Legacy project, simpler mental model |
| Vite + React | SPA, client-only | No SSR needed, fastest dev experience |
| Create React App | Legacy | Avoid for new projects |
Reference Files
| Topic | Load | Use When |
|---|
| Project structure | references/project-structure.md | Setting up or organizing code |
| Components | references/components.md | Building UI components |
| State management | references/state-management.md | Managing app/component state |
| Data fetching | references/data-fetching.md | API calls, server data |
| Forms | references/forms.md | Form handling and validation |
| Auth (client) | references/auth-client.md | Client-side authentication |
Quick Start Patterns
Next.js App Router Page
// app/users/page.tsx
import { getUsers } from '@/lib/api';
import { UserList } from '@/components/users/UserList';
export default async function UsersPage() {
const users = await getUsers();
return (
<main className="container mx-auto py-8">
<h1 className="text-2xl font-bold mb-6">Users</h1>
<UserList users={users} />
</main>
);
}
Client Component
'use client';
import { useState } from 'react';
interface CounterProps {
initialCount?: number;
}
export function Counter({ initialCount = 0 }: CounterProps) {
const [count, setCount] = useState(initialCount);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
API Route (App Router)
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
const users = await db.user.findMany();
return NextResponse.json(users);
}
export async function POST(request: Request) {
const body = await request.json();
const user = await db.user.create({ data: body });
return NextResponse.json(user, { status: 201 });
}
Essential Packages
| Package | Purpose |
|---|
typescript | Type safety |
tailwindcss | Styling |
@tanstack/react-query | Server state |
zustand | Client state |
react-hook-form | Forms |
zod | Validation |
framer-motion | Animations |
lucide-react | Icons |
TypeScript Rules
- Explicit prop types - Interface for every component
- No
any - Use unknown if needed
- Strict mode - Enable in tsconfig
- Type imports - Use
import type when possible
Code Quality Rules
- Functional components - No class components
- Named exports - Except page defaults
- Small files - One component per file
- Custom hooks - Extract reusable logic
- Error boundaries - Wrap key sections
- Loading states - Always handle loading/error