Next.js

Lesson 03

Server vs Client Components

Use Server Components for data and secrets, and Client Components for interactivity.

Good Code

app/reviews/[id]/page.tsx
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>
  );
}

Bad Code

app/reviews/[id]/page.tsx
"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>;
}

Review Notes

What to review

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.

Bad Code

The bad version marks the whole page as client code, moves fetching after hydration, and gives up the server-rendered data path.

Takeaways

  • Do not move a whole route to the client just because one child needs state.