Good Code
The good version keeps the route as a Server Component, fetches the review on the server, and passes only interactive data to a Client Component.
Lesson 03
Use Server Components for data and secrets, and Client Components for interactivity.
import { VoteButton } from "./vote-button";
import { getReview } from "@/lib/reviews";
export default async function ReviewPage({
params,
}: PageProps<"/reviews/[id]">) {
const { id } = await params;
// Server rendering fetches the review before handing votes to a client island.
const review = await getReview(id);
return (
<article>
<h1>{review.title}</h1>
<p>{review.summary}</p>
<VoteButton initialVotes={review.votes} />
</article>
);
}"use client";
import { useEffect, useState } from "react";
export default function ReviewPage() {
const [review, setReview] = useState(null);
// This client boundary moves page data fetching after hydration.
useEffect(() => {
fetch("/api/current-review")
.then((response) => response.json())
.then(setReview);
}, []);
if (!review) {
return <p>Loading...</p>;
}
return <h1>{review.title}</h1>;
}The good version keeps the route as a Server Component, fetches the review on the server, and passes only interactive data to a Client Component.
The bad version marks the whole page as client code, moves fetching after hydration, and gives up the server-rendered data path.