nextjs-server-navigation

安装量: 100
排名: #8291

安装

npx skills add https://github.com/wsimmonds/claude-nextjs-skills --skill nextjs-server-navigation

Next.js: Server Component Navigation Pattern ⚠️ CRITICAL RULE

Server Components use DIFFERENT navigation methods than Client Components!

When requirements call for server-rendered navigation—for example, linking to other pages, redirecting after a check, or demonstrating routing patterns—prefer <Link> and redirect() within Server Components. You still avoid 'use client' unless a client-only API is involved.

The Pattern

Scenario: build a server component that demonstrates proper navigation patterns

✅ CORRECT Solution:

// app/page.tsx (Server Component - NO 'use client'!) import Link from 'next/link';

export default async function Page() { return (

Home

<Link href="/dashboard">Go to Dashboard</Link> <Link href="/profile">View Profile</Link>
); }

❌ WRONG Solution:

// app/page.tsx 'use client'; // ❌ NO! Server components don't need this for navigation!

import { useRouter } from 'next/navigation'; // ❌ Wrong for server components

export default function Page() { const router = useRouter(); // ❌ This is client-side navigation // ... }

Server Navigation Methods Method 1: Link Component (Recommended for Links) // app/page.tsx import Link from 'next/link';

export default async function Page() { // Can still fetch data - this is a server component! const data = await fetchData();

return (

Welcome

  {/* Simple navigation link */}
  <Link href="/about">About Us</Link>

  {/* Dynamic link */}
  <Link href={`/products/${data.productId}`}>View Product</Link>

  {/* Link with styling */}
  <Link href="/dashboard" className="btn-primary">
    Dashboard
  </Link>
</div>

); }

Key Points:

✅ Works in Server Components (no 'use client' needed) ✅ Can be async function ✅ Can fetch data ✅ No hooks required Method 2: redirect() Function (For Conditional Redirects) // app/profile/page.tsx import { redirect } from 'next/navigation'; import { cookies } from 'next/headers';

export default async function ProfilePage() { // Check authentication const cookieStore = await cookies(); const session = cookieStore.get('session');

// Redirect if not authenticated if (!session) { redirect('/login'); }

// Fetch user data const user = await fetchUser(session.value);

return

Welcome, {user.name}!
; }

When to use redirect():

Conditional redirects based on server-side data Authentication checks Permission validation Data-based routing Method 3: Button with Server Action // app/page.tsx import { logout } from './actions';

export default async function Page() { return (

Dashboard

  <form action={logout}>
    <button type="submit">Logout</button>
  </form>
</div>

); }

// app/actions.ts 'use server';

import { redirect } from 'next/navigation';

export async function logout() { // Clear session await clearSession();

// Redirect to login page redirect('/login'); }

Complete Example: Navigation Patterns // app/page.tsx - Demonstrates multiple navigation patterns

import Link from 'next/link'; import { redirect } from 'next/navigation'; import { headers } from 'next/headers';

export default async function HomePage() { // Server-side logic const headersList = await headers(); const userAgent = headersList.get('user-agent');

// Conditional redirect example if (userAgent?.includes('bot')) { redirect('/bot-page'); }

return (

Welcome to Our App

  {/* Navigation Links */}
  <nav>
    <Link href="/about">About</Link>
    <Link href="/products">Products</Link>
    <Link href="/contact">Contact</Link>
  </nav>

  {/* Button-style link */}
  <Link href="/get-started" className="button">
    Get Started
  </Link>

  {/* Dynamic link */}
  <Link href={`/user/${123}`}>View Profile</Link>
</div>

); }

TypeScript: NEVER Use any Type // ❌ WRONG function handleClick(e: any) { ... }

// ✅ CORRECT - Not needed in server components! // Server components don't have onClick handlers

// For client components with handlers: 'use client'; function handleClick(e: React.MouseEvent) { ... }

Server vs Client Navigation Comparison Feature Server Component Client Component <Link> ✅ Yes ✅ Yes redirect() ✅ Yes ❌ No useRouter() ❌ No ✅ Yes usePathname() ❌ No ✅ Yes async function ✅ Yes ❌ No 'use client' ❌ No ✅ Yes Common Mistakes to Avoid ❌ Mistake 1: Adding 'use client' for Navigation // ❌ WRONG 'use client'; // Don't add this just for navigation!

import Link from 'next/link';

export default function Page() { return <Link href="/about">About</Link>; }

// ✅ CORRECT import Link from 'next/link';

// No 'use client' needed! export default async function Page() { return <Link href="/about">About</Link>; }

❌ Mistake 2: Using useRouter() in Server Component // ❌ WRONG import { useRouter } from 'next/navigation'; // This is for CLIENT components!

export default async function Page() { const router = useRouter(); // ERROR! Can't use hooks in server components // ... }

// ✅ CORRECT - Use Link or redirect() import Link from 'next/link'; import { redirect } from 'next/navigation';

export default async function Page() { // Conditional redirect const shouldRedirect = await checkSomething(); if (shouldRedirect) { redirect('/other-page'); }

// Or navigation links return <Link href="/other-page">Go</Link>; }

❌ Mistake 3: Making Component Client-Side for Simple Navigation // ❌ WRONG - Loses server component benefits! 'use client';

export default function Page() { return (

<Link href="/dashboard">Dashboard</Link>
); }

// ✅ CORRECT - Keep it as a server component! export default async function Page() { // Can now fetch data server-side const data = await fetchData();

return (

<Link href="/dashboard">Dashboard</Link>

{data.message}

); }

Advanced Patterns Programmatic Navigation in Server Actions // app/page.tsx import { createPost } from './actions';

export default async function Page() { return (

); }

// app/actions.ts 'use server';

import { redirect } from 'next/navigation';

export async function createPost(formData: FormData) { const title = formData.get('title') as string;

// Save to database const post = await db.posts.create({ title });

// Redirect to the new post redirect(/posts/${post.id}); }

Multiple Links in Server Component // app/page.tsx import Link from 'next/link';

export default async function NavigationPage() { const pages = await fetchPages();

return (

); }

Quick Decision Tree Need navigation in a component? │ ├─ Is it a Server Component (no 'use client')? │ ├─ Static link → Use <Link> │ ├─ Conditional redirect → Use redirect() │ └─ Form submission → Server Action with redirect() │ └─ Is it a Client Component ('use client')? ├─ Link → Use <Link> (works in both!) └─ Programmatic → Use useRouter()

When to Use Client-Side Navigation Instead

Use Client Components ('use client' + useRouter()) ONLY when you need:

Programmatic navigation based on client state Navigation after client-side animations Browser-only APIs (window, localStorage) React hooks (useState, useEffect)

For everything else, use Server Component navigation!

Quick Checklist

When you see "demonstrates navigation patterns":

Create a server component (no 'use client') Import Link from 'next/link' Add <Link> components with href prop Keep component as async if fetching data Do NOT import useRouter from next/navigation Do NOT add 'use client' directive Use proper TypeScript types (no any) Summary

Server Component Navigation:

✅ Use <Link> for navigation links ✅ Use redirect() for conditional redirects ✅ Keep component async if needed ✅ No 'use client' required ✅ No hooks needed

This pattern is simpler and more performant than client-side navigation for static links!

返回排行榜