nextjs-project-manager

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js Project Manager Skill

Next.js 项目开发技能指南

Overview

概述

This skill helps you build production-ready Next.js 14+ applications using the App Router. Use this when working on routing, components, server actions, data fetching, or any Next.js-specific patterns.
本技能可帮助你使用App Router构建可投入生产的Next.js 14+应用程序。适用于处理路由、组件、服务端操作、数据获取或任何Next.js特定模式的场景。

Core Principles

核心原则

1. App Router First

1. 优先使用App Router

  • All routes in
    src/app/
    directory
  • Use
    page.tsx
    for routes,
    layout.tsx
    for shared layouts
  • Server Components by default, Client Components when needed
  • Route groups with
    (group)
    for organization
  • 所有路由位于
    src/app/
    目录下
  • 使用
    page.tsx
    定义路由,
    layout.tsx
    定义共享布局
  • 默认使用Server Components,按需使用Client Components
  • 使用
    (group)
    路由组进行组织

2. Server vs Client Components

2. 服务端组件 vs 客户端组件

Server Components (Default):
  • No "use client" directive needed
  • Can use async/await directly
  • Access database/backend directly
  • Better performance (less JS sent to client)
  • Cannot use hooks or browser APIs
Client Components ("use client"):
  • Use when you need:
    • State (useState, useReducer)
    • Effects (useEffect)
    • Event handlers (onClick, onChange)
    • Browser APIs (localStorage, window)
    • Third-party libraries that use hooks
服务端组件(默认):
  • 无需添加"use client"指令
  • 可直接使用async/await
  • 可直接访问数据库/后端服务
  • 性能更优(发送到客户端的JS代码更少)
  • 无法使用hooks或浏览器API
客户端组件(需添加"use client"):
  • 以下场景需使用客户端组件:
    • 状态管理(useState、useReducer)
    • 副作用处理(useEffect)
    • 事件处理器(onClick、onChange)
    • 浏览器API(localStorage、window)
    • 使用hooks的第三方库

3. Data Fetching Patterns

3. 数据获取模式

Server Components:
typescript
// Direct async fetch in component
export default async function Page() {
  const data = await fetch('https://api.example.com/data')
  const json = await data.json()
  return <div>{json.title}</div>
}
Client Components:
typescript
'use client'
import { useEffect, useState } from 'react'

export default function Page() {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then(setData)
  }, [])

  return <div>{data?.title}</div>
}
服务端组件:
typescript
// Direct async fetch in component
export default async function Page() {
  const data = await fetch('https://api.example.com/data')
  const json = await data.json()
  return <div>{json.title}</div>
}
客户端组件:
typescript
'use client'
import { useEffect, useState } from 'react'

export default function Page() {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then(setData)
  }, [])

  return <div>{data?.title}</div>
}

4. Server Actions

4. 服务端操作

Use Server Actions for form submissions and mutations:
typescript
// app/actions.ts
'use server'

export async function createItem(formData: FormData) {
  const title = formData.get('title')
  // Database operation
  await db.insert({ title })
  revalidatePath('/items')
  redirect('/items')
}

// app/form.tsx
'use client'
import { createItem } from './actions'

export function Form() {
  return (
    <form action={createItem}>
      <input name="title" />
      <button type="submit">Create</button>
    </form>
  )
}
使用Server Actions处理表单提交和数据变更:
typescript
// app/actions.ts
'use server'

export async function createItem(formData: FormData) {
  const title = formData.get('title')
  // Database operation
  await db.insert({ title })
  revalidatePath('/items')
  redirect('/items')
}

// app/form.tsx
'use client'
import { createItem } from './actions'

export function Form() {
  return (
    <form action={createItem}>
      <input name="title" />
      <button type="submit">Create</button>
    </form>
  )
}

Common Patterns

常见模式

Route Structure

路由结构

src/app/
├── (auth)/
│   ├── login/
│   │   └── page.tsx
│   └── signup/
│       └── page.tsx
├── (dashboard)/
│   ├── layout.tsx          # Shared dashboard layout
│   ├── page.tsx            # Dashboard home
│   └── settings/
│       └── page.tsx
├── api/
│   └── endpoint/
│       └── route.ts        # API routes
├── layout.tsx              # Root layout
└── page.tsx                # Home page
src/app/
├── (auth)/
│   ├── login/
│   │   └── page.tsx
│   └── signup/
│       └── page.tsx
├── (dashboard)/
│   ├── layout.tsx          # Shared dashboard layout
│   ├── page.tsx            # Dashboard home
│   └── settings/
│       └── page.tsx
├── api/
│   └── endpoint/
│       └── route.ts        # API routes
├── layout.tsx              # Root layout
└── page.tsx                # Home page

Layouts

布局

typescript
// app/(dashboard)/layout.tsx
import { Sidebar } from '@/components/sidebar'

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className="flex">
      <Sidebar />
      <main className="flex-1">{children}</main>
    </div>
  )
}
typescript
// app/(dashboard)/layout.tsx
import { Sidebar } from '@/components/sidebar'

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className="flex">
      <Sidebar />
      <main className="flex-1">{children}</main>
    </div>
  )
}

Loading States

加载状态

typescript
// app/dashboard/loading.tsx
export default function Loading() {
  return <div>Loading...</div>
}
typescript
// app/dashboard/loading.tsx
export default function Loading() {
  return <div>Loading...</div>
}

Error Handling

错误处理

typescript
// app/dashboard/error.tsx
'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={reset}>Try again</button>
    </div>
  )
}
typescript
// app/dashboard/error.tsx
'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={reset}>Try again</button>
    </div>
  )
}

Metadata

元数据

typescript
// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Page Title',
  description: 'Page description',
}

export default function Page() {
  return <div>Content</div>
}
typescript
// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Page Title',
  description: 'Page description',
}

export default function Page() {
  return <div>Content</div>
}

API Routes

API路由

typescript
// app/api/items/route.ts
import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
  const items = await db.getItems()
  return NextResponse.json({ items })
}

export async function POST(request: NextRequest) {
  const body = await request.json()
  const item = await db.createItem(body)
  return NextResponse.json({ item }, { status: 201 })
}
typescript
// app/api/items/route.ts
import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
  const items = await db.getItems()
  return NextResponse.json({ items })
}

export async function POST(request: NextRequest) {
  const body = await request.json()
  const item = await db.createItem(body)
  return NextResponse.json({ item }, { status: 201 })
}

Dynamic Routes

动态路由

typescript
// app/posts/[id]/page.tsx
export default function Post({ params }: { params: { id: string } }) {
  return <div>Post {params.id}</div>
}

// Generate static params
export async function generateStaticParams() {
  const posts = await getPosts()
  return posts.map((post) => ({ id: post.id }))
}
typescript
// app/posts/[id]/page.tsx
export default function Post({ params }: { params: { id: string } }) {
  return <div>Post {params.id}</div>
}

// Generate static params
export async function generateStaticParams() {
  const posts = await getPosts()
  return posts.map((post) => ({ id: post.id }))
}

Middleware

中间件

typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Check auth, redirect, rewrite, etc.
  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}
typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Check auth, redirect, rewrite, etc.
  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}

Environment Variables

环境变量

typescript
// Access in Server Components or Server Actions
const apiKey = process.env.API_KEY

// Access in Client Components (must be prefixed with NEXT_PUBLIC_)
const publicKey = process.env.NEXT_PUBLIC_API_KEY
typescript
// Access in Server Components or Server Actions
const apiKey = process.env.API_KEY

// Access in Client Components (must be prefixed with NEXT_PUBLIC_)
const publicKey = process.env.NEXT_PUBLIC_API_KEY

Best Practices Checklist

最佳实践清单

  • Use Server Components by default
  • Add "use client" only when necessary
  • Use Server Actions for mutations
  • Implement loading.tsx for loading states
  • Implement error.tsx for error boundaries
  • Use route groups for organization
  • Add metadata to all pages
  • Use TypeScript for type safety
  • Implement proper error handling
  • Use middleware for auth checks
  • Optimize images with next/image
  • Use dynamic imports for large components
  • 默认使用Server Components
  • 仅在必要时添加"use client"指令
  • 使用Server Actions处理数据变更
  • 实现loading.tsx处理加载状态
  • 实现error.tsx作为错误边界
  • 使用路由组进行代码组织
  • 为所有页面添加元数据
  • 使用TypeScript保证类型安全
  • 实现完善的错误处理
  • 使用中间件进行权限校验
  • 使用next/image优化图片
  • 对大型组件使用动态导入

Debugging Tips

调试技巧

  1. Hydration Errors: Check for server/client mismatches
  2. "use client" Errors: Missing directive on component using hooks
  3. Cannot Access Browser APIs: Move to client component
  4. Data Not Updating: Use revalidatePath() or revalidateTag()
  5. Build Errors: Check for async components without proper typing
  1. Hydration Errors:检查服务端/客户端内容不匹配问题
  2. "use client" Errors:检查使用hooks的组件是否缺少指令
  3. 无法访问浏览器API:将代码迁移到客户端组件
  4. 数据未更新:使用revalidatePath()或revalidateTag()
  5. 构建错误:检查异步组件是否有正确的类型定义

Performance Optimization

性能优化

  • Use React Suspense for loading states
  • Implement streaming with loading.tsx
  • Use dynamic imports for code splitting
  • Optimize images with next/image
  • Use Font optimization with next/font
  • Implement ISR (Incremental Static Regeneration)
  • Use caching with fetch options
  • 使用React Suspense处理加载状态
  • 通过loading.tsx实现流式渲染
  • 使用动态导入进行代码分割
  • 使用next/image优化图片
  • 使用next/font优化字体
  • 实现ISR(增量静态再生)
  • 通过fetch选项配置缓存

When to Use This Skill

适用场景

Invoke this skill when:
  • Creating new routes or pages
  • Setting up layouts
  • Implementing forms with Server Actions
  • Debugging Next.js-specific errors
  • Optimizing performance
  • Setting up middleware
  • Creating API routes
  • Working with metadata
在以下场景调用本技能:
  • 创建新路由或页面
  • 设置布局
  • 使用Server Actions实现表单
  • 调试Next.js特定错误
  • 优化性能
  • 设置中间件
  • 创建API路由
  • 处理元数据