/** * Next.js App Router Page Template * * This template demonstrates best practices for creating pages * in Next.js 14+ App Router with Server Components. * * Key Features: * - Server Component by default (no 'use client' needed) * - SEO metadata generation * - Suspense boundaries for streaming * - Error handling * - TypeScript types */ import { Metadata } from 'next'; import { Suspense } from 'react'; import { notFound } from 'next/navigation'; // Components import { PageHeader } from '@/components/organisms/PageHeader'; import { DataTable } from '@/components/organisms/DataTable'; import { Skeleton } from '@/components/atoms/Skeleton'; // ============================================================================ // TYPES // ============================================================================ interface PageProps { params: { id: string; }; searchParams: { page?: string; sort?: string; }; } // ============================================================================ // METADATA (SEO) // ============================================================================ /** * Generate static metadata for SEO * * This function runs on the server and generates metadata * for search engines and social media. */ export async function generateMetadata({ params, }: PageProps): Promise { // Fetch data needed for metadata const data = await fetchData(params.id); if (!data) { return { title: 'Not Found', }; } return { title: `${data.title} | Your App Name`, description: data.description, openGraph: { title: data.title, description: data.description, images: [data.imageUrl], }, twitter: { card: 'summary_large_image', title: data.title, description: data.description, images: [data.imageUrl], }, }; } /** * Optional: Generate static paths for Static Site Generation (SSG) * * Uncomment this function if you want to pre-render pages at build time. */ // export async function generateStaticParams() { // const items = await fetchAllItems(); // // return items.map((item) => ({ // id: item.id, // })); // } // ============================================================================ // DATA FETCHING // ============================================================================ /** * Fetch data on the server * * This runs on the server, so you can safely access databases, * private APIs, etc. */ async function fetchData(id: string) { const response = await fetch(`https://api.example.com/items/${id}`, { next: { revalidate: 3600, // ISR: Revalidate every hour // OR use 'force-cache' for static generation // OR use 'no-store' for dynamic rendering }, }); if (!response.ok) { return null; } return response.json(); } async function fetchRelatedData(filters: { page: number; sort: string }) { const response = await fetch( `https://api.example.com/related?page=${filters.page}&sort=${filters.sort}`, { next: { revalidate: 60 }, // Revalidate every minute } ); return response.json(); } // ============================================================================ // PAGE COMPONENT // ============================================================================ /** * Page Component (Server Component by default) * * Server Components: * - Run on the server only * - Can access backend resources directly * - Don't add JavaScript to the client bundle * - Can't use hooks like useState, useEffect * - Can't add event handlers */ export default async function Page({ params, searchParams }: PageProps) { // ======================================================================== // DATA FETCHING (Server-side) // ======================================================================== // Parse search params const page = searchParams.page ? parseInt(searchParams.page) : 1; const sort = searchParams.sort || 'desc'; // Fetch data in parallel for performance const [mainData, relatedData] = await Promise.all([ fetchData(params.id), fetchRelatedData({ page, sort }), ]); // Handle not found if (!mainData) { notFound(); // Renders app/not-found.tsx } // ======================================================================== // RENDER // ======================================================================== return (
{/* Page Header */} {/* Main Content */}

Details

ID: {mainData.id}

Created: {mainData.createdAt}

{/* Related Data with Suspense */}

Related Items

}>
); } // ============================================================================ // CLIENT COMPONENT EXAMPLE (if needed) // ============================================================================ /** * If you need interactivity, create a separate Client Component: * * 'use client'; * * export function InteractiveSection({ initialData }) { * const [state, setState] = useState(initialData); * * return ( *
* *
* ); * } * * Then use it in the Server Component: * */