Back
Syntax
Study
Editor
Mode:
HTML
CSS
JavaScript
PHP
Reset
Run »
HTML / CSS / JS
// app/blog/[slug]/page.tsx — Static generation with ISR import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; interface Post { slug: string; title: string; content: string; publishedAt: string; } // Tell Next.js which slugs to pre-render at build time export async function generateStaticParams() { const res = await fetch('https://api.example.com/posts?fields=slug'); const posts: Pick<Post, 'slug'>[] = await res.json(); return posts.map((post) => ({ slug: post.slug })); } // Revalidate every hour (ISR) export const revalidate = 3600; // Allow on-demand generation for slugs not in generateStaticParams export const dynamicParams = true; async function getPost(slug: string): Promise<Post | null> { const res = await fetch(`https://api.example.com/posts/${slug}`, { next: { revalidate: 3600, tags: [`post-${slug}`] }, }); if (!res.ok) return null; return res.json(); } export async function generateMetadata({ params, }: { params: { slug: string }; }): Promise<Metadata> { const post = await getPost(params.slug); return { title: post?.title ?? 'Post not found' }; } export default async function BlogPostPage({ params, }: { params: { slug: string }; }) { const post = await getPost(params.slug); if (!post) notFound(); return ( <article> <h1>{post.title}</h1> <time>{post.publishedAt}</time> <div dangerouslySetInnerHTML={{ __html: post.content }} /> </article> ); }
Result
Open