)
}
```
**3. UI Components** (Reusable, no business logic):
```typescript
// components/ui/button.tsx
export function Button({ children, variant = 'primary', ...props }) {
return (
)
}
```
### Component Best Practices
```typescript
// ✅ Good: Small, focused, typed
interface UserProfileProps {
user: User
onEdit?: () => void
}
export function UserProfile({ user, onEdit }: UserProfileProps) {
return (
{onEdit && }
)
}
// ❌ Bad: Giant, untyped, unclear
export function UserProfile(props) {
// 500 lines of JSX, multiple responsibilities
return
...
}
```
---
## State Management
### Decision Tree
```
How many components need this state?
│
├─ One component → useState
├─ Parent + children → Props or useState + props
├─ Siblings → Lift to common parent
├─ Widely used (theme, auth) → Context API
└─ Complex app state → Zustand or Redux
```
### Local State (useState)
```typescript
// For component-level state
function Counter() {
const [count, setCount] = useState(0)
const [isOpen, setIsOpen] = useState(false)
return (
)
}
```
### Context API
```typescript
// For app-wide state (theme, auth, user)
const UserContext = createContext(undefined)
export function UserProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState(null)
return (
{children}
)
}
export function useUser() {
const context = useContext(UserContext)
if (!context) throw new Error('useUser must be within UserProvider')
return context
}
```
### Zustand (Recommended for Complex State)
```typescript
import { create } from 'zustand'
interface CounterStore {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 })
}))
// Usage
function Counter() {
const { count, increment } = useCounterStore()
return
}
```
---
## Data Fetching
### React Query (Recommended)
```typescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
// Query (GET)
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000 // 5 minutes
})
if (isLoading) return
if (error) return
return
}
// Mutation (POST, PUT, DELETE)
function CreateUser() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: createUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
}
})
return (
)
}
```
### Next.js Server Components (App Router)
```typescript
// app/users/page.tsx
// Server Component - fetches on server
export default async function UsersPage() {
const users = await fetchUsers() // Runs on server
return
}
// Client Component - for interactivity
'use client'
export function UserList({ users }: { users: User[] }) {
const [selected, setSelected] = useState(null)
return (
{users.map(user => (
setSelected(user.id)}
/>
))}
)
}
```
---
## Form Handling
### React Hook Form (Recommended)
```typescript
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
const loginSchema = z.object({
email: z.string().email('Invalid email address'),
password: z.string().min(8, 'Password must be at least 8 characters')
})
type LoginForm = z.infer
function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting }
} = useForm({
resolver: zodResolver(loginSchema)
})
const onSubmit = async (data: LoginForm) => {
await login(data)
}
return (
)
}
```
---
## Styling
### Tailwind CSS (Recommended)
```typescript
// Install: @shadcn/ui for component library
function Button({ variant = 'primary', children, ...props }) {
return (
)
}
```
### CSS Modules (Alternative)
```typescript
// Button.module.css
.button {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
}
.primary {
background-color: blue;
color: white;
}
// Button.tsx
import styles from './Button.module.css'
export function Button({ variant = 'primary', children }) {
return (
)
}
```
---
## Performance Optimization
### React Optimization
```typescript
import { memo, useMemo, useCallback } from 'react'
// 1. Memoize expensive calculations
function DataTable({ data }) {
const sortedData = useMemo(
() => data.sort((a, b) => a.name.localeCompare(b.name)),
[data]
)
return