Next.js 动态路由详解

Next.js 动态路由详解

动态路由是 Next.js 的核心功能之一,它允许你根据动态参数创建页面,非常适合构建博客、电商产品页、用户资料等需要根据数据动态生成的页面。

基本概念

Next.js 的动态路由是通过文件系统实现的,你只需要在 pages 目录下创建特殊命名的文件或文件夹:

  • pages/posts/[id].js - 匹配 /posts/1, /posts/abc
  • pages/categories/[category]/[id].js - 匹配 /categories/books/123

基本使用示例

1. 单参数动态路由

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

export default function Post() {
  const router = useRouter()
  const { id } = router.query

  return <div>Post ID: {id}</div>
}

应用场景:博客文章详情页,根据ID从API或数据库获取对应文章内容。

2. 多段动态路由

// pages/products/[category]/[productId].js
export default function Product() {
  const { category, productId } = useRouter().query

  return (
    <div>
      <h1>Product Details</h1>
      <p>Category: {category}</p>
      <p>Product ID: {productId}</p>
    </div>
  )
}

应用场景:电商网站产品页,按分类和产品ID展示商品详情。

高级用法

1. 预渲染与数据获取

Next.js 允许在构建时或请求时预渲染动态路由页面。

// pages/posts/[id].js
export async function getStaticPaths() {
  // 获取所有可能的ID
  const res = await fetch('https://api.example.com/posts')
  const posts = await res.json()

  // 返回路径数组
  const paths = posts.map(post => ({
    params: { id: post.id.toString() }
  }))

  return { paths, fallback: false }
}

export async function getStaticProps({ params }) {
  // 根据ID获取文章数据
  const res = await fetch(`https://api.example.com/posts/${params.id}`)
  const post = await res.json()

  return { props: { post } }
}

export default function Post({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

应用场景:静态博客,在构建时生成所有文章页面,提供最佳性能。

2. 捕获所有路由

// pages/docs/[...slug].js
export default function Docs() {
  const { slug } = useRouter().query

  return (
    <div>
      <h1>Documentation Page</h1>
      <p>Current path: {slug?.join('/')}</p>
    </div>
  )
}

访问 /docs/a/b/c 会得到 slug: ['a', 'b', 'c']

应用场景:文档网站,支持多级目录结构。

3. 可选捕获所有路由

// pages/blog/[[...slug]].js
export default function Blog() {
  const { slug } = useRouter().query

  return (
    <div>
      {slug ? (
        <p>Viewing blog post: {slug.join('/')}</p>
      ) : (
        <p>Viewing blog homepage</p>
      )}
    </div>
  )
}

这会匹配 /blog, /blog/a, /blog/a/b 等。

应用场景:博客首页和文章详情页使用同一个组件。

实际应用场景示例

场景1:用户个人资料页

// pages/users/[username].js
import { getUserProfile } from '../../lib/api'

export async function getServerSideProps({ params }) {
  try {
    const user = await getUserProfile(params.username)
    return { props: { user } }
  } catch (error) {
    return { notFound: true }
  }
}

export default function UserProfile({ user }) {
  return (
    <div className="profile">
      <img src={user.avatar} alt={user.name} />
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
      {/* 其他个人资料信息 */}
    </div>
  )
}

场景2:电商产品分类和详情页

// pages/shop/[...slugs].js
export async function getStaticPaths() {
  // 获取所有产品路径
  const products = await getAllProducts()
  const paths = products.map(product => ({
    params: { slugs: [product.category, product.slug] }
  }))

  return { paths, fallback: 'blocking' }
}

export async function getStaticProps({ params }) {
  const [category, productSlug] = params.slugs
  const product = await getProductDetails(category, productSlug)

  return { 
    props: { product },
    revalidate: 60 // ISR: 每60秒重新验证
  }
}

export default function ProductPage({ product }) {
  // 渲染产品详情
}

最佳实践

  1. 合理使用预渲染策略

    • 使用 getStaticProps + getStaticPaths 构建时生成静态页面
    • 使用 getServerSideProps 服务端渲染动态内容
    • 使用 fallback: true'blocking' 处理新增内容
  2. 处理未找到的情况

    export async function getStaticProps({ params }) {
      const post = await getPost(params.id)
      if (!post) {
        return { notFound: true }
      }
      return { props: { post } }
    }
    
  3. 类型安全(使用 TypeScript):

    import { GetStaticPaths, GetStaticProps } from 'next'
    
    interface PostProps {
      post: {
        id: string
        title: string
        content: string
      }
    }
    
    export const getStaticPaths: GetStaticPaths = async () => {
      // ...
    }
    
    export const getStaticProps: GetStaticProps<PostProps> = async ({ params }) => {
      // ...
    }
    

动态路由是 Next.js 最强大的功能之一,合理使用可以构建出既保持良好SEO又能提供优秀用户体验的现代Web应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小灰灰学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值