Next.js

Lesson 05

Server-side data fetching

Fetch route data on the server when the page needs it before rendering.

Good Code

app/articles/[slug]/page.tsx
import { notFound } from "next/navigation";
import { getArticleBySlug } from "@/lib/articles";

export default async function ArticlePage({
  params,
}: PageProps<"/articles/[slug]">) {
  const { slug } = await params;
  // Fetch essential page data on the server and use notFound for missing slugs.
  const article = await getArticleBySlug(slug);

  if (!article) {
    notFound();
  }

  return (
    <article>
      <h1>{article.title}</h1>
      <p>{article.excerpt}</p>
    </article>
  );
}

Bad Code

app/articles/[slug]/article-client.tsx
"use client";

import { useEffect, useState } from "react";

export function ArticleClient({ slug }: { slug: string }) {
  const [article, setArticle] = useState(null);

  // Hydration-gated fetching delays page data and adds an avoidable API hop.
  useEffect(() => {
    fetch("/api/articles/" + slug)
      .then((response) => response.json())
      .then(setArticle);
  }, [slug]);

  if (!article) {
    return <p>Loading article...</p>;
  }

  return <h1>{article.title}</h1>;
}

Review Notes

What to review

Good Code

The good version fetches the article before rendering the page and uses notFound() for a missing slug.

Bad Code

The bad version delays essential page data until after client hydration and adds an API hop for data the server route can already read.

Takeaways

  • Server Components can fetch data close to the source without exposing secrets to the client.