Skip to content

Next.js 开发指南

Next.js 是 React 的生产级框架,提供了服务端渲染、静态生成、路由等开箱即用的功能。本文将介绍 Next.js 的核心概念和开发实践。

Next.js 简介

Next.js 是 Vercel 开发的 React 框架,具有以下特性:

  • 服务端渲染(SSR):提升首屏加载速度和 SEO
  • 静态站点生成(SSG):预渲染页面,提升性能
  • 自动代码分割:按页面自动分割代码
  • 文件系统路由:基于文件系统的路由系统
  • API Routes:内置 API 路由支持

项目初始化

创建项目

bash
npx create-next-app@latest my-app
cd my-app
npm run dev

项目结构

my-app/
├── pages/          # 页面目录(路由)
│   ├── index.js    # 首页 (/)
│   ├── about.js    # 关于页 (/about)
│   └── api/        # API 路由
├── public/         # 静态资源
├── styles/         # 样式文件
└── components/     # 组件目录

路由系统

文件系统路由

Next.js 使用文件系统作为路由系统:

javascript
// pages/index.js - 对应路由 /
export default function Home() {
  return <h1>首页</h1>
}

// pages/about.js - 对应路由 /about
export default function About() {
  return <h1>关于我们</h1>
}

// pages/blog/[id].js - 动态路由 /blog/123
export default function BlogPost({ id }) {
  return <h1>文章 {id}</h1>
}

动态路由

javascript
// pages/blog/[id].js
import { useRouter } from 'next/router'

export default function BlogPost() {
  const router = useRouter()
  const { id } = router.query
  
  return <h1>文章 ID: {id}</h1>
}

// 多个动态参数
// pages/shop/[...slug].js - 捕获所有路由
// /shop/a -> { slug: ['a'] }
// /shop/a/b -> { slug: ['a', 'b'] }

编程式导航

javascript
import Link from 'next/link'
import { useRouter } from 'next/router'

function Navigation() {
  const router = useRouter()
  
  return (
    <nav>
      {/* 使用 Link 组件 */}
      <Link href="/about">
        <a>关于</a>
      </Link>
      
      {/* 编程式导航 */}
      <button onClick={() => router.push('/about')}>
        跳转到关于页
      </button>
    </nav>
  )
}

数据获取

getStaticProps(静态生成)

在构建时获取数据,生成静态页面。

javascript
// pages/blog/[id].js
export default function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

export async function getStaticProps({ params }) {
  const post = await fetchPost(params.id)
  
  return {
    props: {
      post
    },
    revalidate: 60 // ISR: 60秒后重新生成
  }
}

export async function getStaticPaths() {
  const posts = await fetchAllPosts()
  const paths = posts.map(post => ({
    params: { id: post.id.toString() }
  }))
  
  return {
    paths,
    fallback: false // 或 'blocking' 或 true
  }
}

getServerSideProps(服务端渲染)

每次请求时在服务端获取数据。

javascript
// pages/user/[id].js
export default function User({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  )
}

export async function getServerSideProps({ params }) {
  const user = await fetchUser(params.id)
  
  if (!user) {
    return {
      notFound: true
    }
  }
  
  return {
    props: {
      user
    }
  }
}

客户端数据获取

使用 useEffect 或 SWR/React Query 在客户端获取数据。

javascript
import { useState, useEffect } from 'react'

function UserProfile({ userId }) {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data)
        setLoading(false)
      })
  }, [userId])
  
  if (loading) return <div>加载中...</div>
  return <div>{user.name}</div>
}

API Routes

Next.js 允许在 pages/api 目录下创建 API 路由。

javascript
// pages/api/users/[id].js
export default function handler(req, res) {
  const { id } = req.query
  
  if (req.method === 'GET') {
    const user = getUserById(id)
    res.status(200).json(user)
  } else if (req.method === 'POST') {
    const user = createUser(req.body)
    res.status(201).json(user)
  } else {
    res.setHeader('Allow', ['GET', 'POST'])
    res.status(405).end(`Method ${req.method} Not Allowed`)
  }
}

样式处理

CSS Modules

javascript
// styles/Button.module.css
.button {
  padding: 10px 20px;
  background: blue;
  color: white;
}

// components/Button.js
import styles from '../styles/Button.module.css'

export default function Button() {
  return <button className={styles.button}>按钮</button>
}

全局样式

javascript
// styles/globals.css
body {
  margin: 0;
  font-family: sans-serif;
}

// pages/_app.js
import '../styles/globals.css'

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Tailwind CSS

bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
javascript
// tailwind.config.js
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

图片优化

Next.js 提供了优化的 Image 组件。

javascript
import Image from 'next/image'

function MyComponent() {
  return (
    <Image
      src="/images/hero.jpg"
      alt="Hero image"
      width={800}
      height={600}
      priority // 优先加载
    />
  )
}

环境变量

javascript
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
SECRET_KEY=your-secret-key

// 使用
// 客户端可访问(NEXT_PUBLIC_ 前缀)
const apiUrl = process.env.NEXT_PUBLIC_API_URL

// 仅服务端可访问
const secretKey = process.env.SECRET_KEY

部署

Vercel 部署(推荐)

bash
npm install -g vercel
vercel

静态导出

javascript
// next.config.js
module.exports = {
  output: 'export',
  images: {
    unoptimized: true
  }
}
bash
npm run build
# 生成 out/ 目录,可以部署到任何静态托管服务

最佳实践

  1. 使用 TypeScript:提供类型安全
  2. 代码分割:利用 Next.js 的自动代码分割
  3. 图片优化:使用 Next.js Image 组件
  4. SEO 优化:使用 Head 组件设置 meta 标签
  5. 性能监控:使用 Web Vitals 监控性能

总结

Next.js 为 React 应用提供了完整的解决方案,包括路由、数据获取、样式处理等。通过合理使用 Next.js 的特性,可以构建高性能、SEO 友好的 React 应用。掌握 Next.js 是现代 React 开发的重要技能。


辛田信息技术 · 内部技术分享 · 仅供学习与参考