Client Components
Interactive UI with hooks, browser APIs, and event handlers — scoped behind the client boundary.
When You Need Client Components
Add `"use client"` at the top of files that use useState, useEffect, useReducer, useContext, or event handlers (onClick, onChange). Browser-only APIs — localStorage, window, geolocation, IntersectionObserver — require client execution.
Third-party libraries built for SPA React often assume client environment. Wrap them in thin client wrapper components rather than marking entire pages client.
- Hooks and events require client
- Browser APIs require client
- Wrap third-party widgets in client shells
'use client';
import { useState } from 'react';
export function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}Minimize Client Bundle Impact
Push the client boundary as deep as possible. A page with one interactive button should not mark the entire page client — extract the button to `SubmitButton.tsx` with `"use client"` and import it into the server page.
Analyze bundles with `@next/bundle-analyzer`. Client imports pull their dependency trees into the browser bundle — heavy charting libraries belong in dynamically imported client components.
- Client boundary as deep as possible
- Dynamic import for heavy client libs
- Analyze bundle impact per client file
Providers and Context
Context providers must be Client Components because context uses React state internally. Place ThemeProvider, QueryClientProvider, and SessionProvider in a client layout wrapper near root.
Pass server-fetched initial data as props into providers that hydrate client cache (TanStack Query dehydrate/hydrate pattern). Avoid fetching the same data twice — server fetch once, hydrate client.
- Providers are client components
- Hydrate client cache from server props
- Avoid duplicate server/client fetching
Interactivity with Server Data
Server Components pass fetched data as props to Client Components for interactive rendering — charts, sortable tables, filters. Mutations call Server Actions or Route Handlers rather than exposing database credentials client-side.
Optimistic updates with useOptimistic improve mutation UX while server confirms. Roll back optimistic state on server error responses.
- Server data as props to client UI
- Mutations via Server Actions
- useOptimistic for mutation UX
Testing Client Components
Test client components with React Testing Library in jsdom. Mock Server Actions and next/navigation hooks. Integration tests render client components within provider wrappers matching production.
Storybook documents client component states — interactions, loading, error. Keep stories colocated with components for design review.
- RTL with mocked navigation/actions
- Provider wrappers in tests
- Storybook for interaction states