The 'use client' Directive
To use React hooks (useState, useEffect) or event listeners, you must mark a component as a Client Component.
'use client' // Must be at the very top
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
Note: "Client Component" doesn't mean it only runs on the client. It is pre-rendered on the server (SSR) and then hydrated on the client.
When to use Client Components?
| Use Case | Server Component | Client Component |
|---|---|---|
| Fetch data | ✅ (Preferred) | ⚠️ (Use SWR/React Query) |
| Access Backend Resources (DB) | ✅ | ❌ |
| Keep sensitive info (API keys) | ✅ | ❌ |
| Add interactivity (onClick) | ❌ | ✅ |
| Use State / Lifecycle Effects | ❌ | ✅ |
| Use Browser APIs (localStorage) | ❌ | ✅ |
Composition Patterns
Avoid making everything a Client Component. Move interactivity to the leaves of your component tree.
Passing Server Components as Props
You cannot import a Server Component into a Client Component directly if you need it to remain a Server Component. Instead, pass it as children.
// app/page.js (Server)
import ClientWrapper from './client-wrapper'
import ServerContent from './server-content'
export default function Page() {
return (
<ClientWrapper>
<ServerContent /> {/* Remains a Server Component! */}
</ClientWrapper>
)
}
// app/client-wrapper.js (Client)
'use client'
import { useState } from 'react'
export default function ClientWrapper({ children }) {
const [open, setOpen] = useState(false)
return (
<div>
<button onClick={() => setOpen(!open)}>Toggle</button>
{open && children}
</div>
)
}
Next.js Specific Hooks
Hooks from next/navigation are for Client Components.
useRouter(): Programmatic navigation.usePathname(): Get current URL path.useSearchParams(): Get query string parameters.useParams(): Get dynamic route parameters.