S
Server Components
Type-safe Server Components with async data fetching and proper typing for Next.js App Router.
Code
typescript
1// app/users/page.tsx - Server Component (default in App Router)2interface User {3 id: number;4 name: string;5 email: string;6 role: "admin" | "user";7}8 9interface UsersPageProps {10 searchParams: Promise<{ page?: string; role?: string }>;11}12 13async function getUsers(page: number, role?: string): Promise<User[]> {14 const params = new URLSearchParams({ page: String(page) });15 if (role) params.set("role", role);16 17 const res = await fetch(`https://api.example.com/users?${params}`, {18 next: { revalidate: 60 }, // ISR: revalidate every 60 seconds19 });20 21 if (!res.ok) throw new Error("Failed to fetch users");22 return res.json();23}24 25export default async function UsersPage({ searchParams }: UsersPageProps) {26 const { page = "1", role } = await searchParams;27 const users = await getUsers(parseInt(page), role);28 29 return (30 <div>31 <h1>Users</h1>32 <ul>33 {users.map((user) => (34 <li key={user.id}>35 {user.name} ({user.email}) - {user.role}36 </li>37 ))}38 </ul>39 </div>40 );41}42 43// app/users/[id]/page.tsx - Dynamic route with params44interface UserPageProps {45 params: Promise<{ id: string }>;46}47 48async function getUser(id: string): Promise<User> {49 const res = await fetch(`https://api.example.com/users/${id}`, {50 cache: "no-store", // Dynamic data51 });52 if (!res.ok) throw new Error("User not found");53 return res.json();54}55 56export async function generateMetadata({ params }: UserPageProps) {57 const { id } = await params;58 const user = await getUser(id);59 return {60 title: user.name,61 description: `Profile of ${user.name}`,62 };63}64 65export default async function UserPage({ params }: UserPageProps) {66 const { id } = await params;67 const user = await getUser(id);68 69 return (70 <div>71 <h1>{user.name}</h1>72 <p>Email: {user.email}</p>73 <p>Role: {user.role}</p>74 </div>75 );76}77 78// Generate static paths79export async function generateStaticParams(): Promise<{ id: string }[]> {80 const users = await getUsers(1);81 return users.map((user) => ({ id: String(user.id) }));82}Run this example locally
$ npx create-next-app@latest --typescript