nextjs-project-manager
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNext.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 directory
src/app/ - Use for routes,
page.tsxfor shared layoutslayout.tsx - Server Components by default, Client Components when needed
- Route groups with for organization
(group)
- 所有路由位于目录下
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 pagesrc/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 pageLayouts
布局
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_KEYtypescript
// 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_KEYBest 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
调试技巧
- Hydration Errors: Check for server/client mismatches
- "use client" Errors: Missing directive on component using hooks
- Cannot Access Browser APIs: Move to client component
- Data Not Updating: Use revalidatePath() or revalidateTag()
- Build Errors: Check for async components without proper typing
- Hydration Errors:检查服务端/客户端内容不匹配问题
- "use client" Errors:检查使用hooks的组件是否缺少指令
- 无法访问浏览器API:将代码迁移到客户端组件
- 数据未更新:使用revalidatePath()或revalidateTag()
- 构建错误:检查异步组件是否有正确的类型定义
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路由
- 处理元数据