Next.js Lesson 6: Client Components
Client Components are for interactivity — anything with state, effects, or event handlers needs “use client”. The rule: server by default, client only when needed.
When to Use Client Components
"use client";
// Client Components are needed for:
// ✅ useState, useEffect, custom hooks
// ✅ onClick, onChange, event handlers
// ✅ Browser APIs (localStorage, window, navigator)
// ✅ useRouter, usePathname hooks
// ✅ Real-time updates
// ✅ Animations
import { useState } from "react";
export default function LikeButton({ postId }: { postId: number }) {
const [liked, setLiked] = useState(false);
const [count, setCount] = useState(0);
return (
<button onClick={() => {
setLiked(!liked);
setCount(c => liked ? c - 1 : c + 1);
}}>
{liked ? "❤️" : "🤍"} {count}
</button>
);
}
Composing Server and Client
// ✅ Correct: Server Component using Client Component
// app/blog/[id]/page.tsx (Server Component)
import LikeButton from "@/components/LikeButton"; // Client
async function BlogPost({ params }: { params: { id: string } }) {
const post = await db.getPost(params.id); // server-only operation
return (
<article>
<h1>{post.title}</h1> {/* server */}
<p>{post.content}</p> {/* server */}
<LikeButton postId={post.id} /> {/* client */}
</article>
);
}
// ✅ Pass server data down to client as props
// ❌ Cannot import server-only code INTO a client component
The Decision Rule
// Ask: "Does this need to be interactive?"
// No → Server Component (default)
// Yes → Add "use client" + useState/events
// Minimize client components at the LEAVES of your tree
// Not: entire page as client
// Yes: just the interactive button/form as client
🏋️ Practice Task
Split a ProductPage into server + client parts: Server part: fetch product data (from jsonplaceholder), display title, price, description. Client part: “Add to Cart” button with quantity selector (useState). The server fetches, the client handles interactions.
💡 Hint: Server: async function ProductPage() { const product = await fetch(…) }. Client: “use client”; function AddToCart({productId}) { const [qty, setQty] = useState(1); }