Good Code
The good version fetches the article before rendering the page and uses notFound() for a missing slug.
Lesson 05
Fetch route data on the server when the page needs it before rendering.
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>
);
}"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>;
}The good version fetches the article before rendering the page and uses notFound() for a missing slug.
The bad version delays essential page data until after client hydration and adds an API hop for data the server route can already read.