You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在NextJS 13中使用getStaticProps实现分页的方式是否合理?

Next.js 13 分页实现规范分析

你的当前实现逻辑上可以运行,但从性能、扩展性和Next.js最佳实践角度来看,存在不少可优化的点,具体分析和改进方向如下:

现有实现的问题

  1. 全量数据拉取的性能隐患
    你通过getStaticProps在构建阶段一次性拉取所有车手数据,虽然前端分页切换流畅,但如果未来F1车手数据量增长,会导致:

    • 项目构建时间大幅延长
    • 页面初始加载的JS包体积膨胀,拖慢首屏加载速度
    • 无法获取构建完成后的最新数据(除非重新触发构建)
  2. 分页无边界校验
    当前逻辑没有限制page的取值范围,当用户手动修改URL或误触按钮导致page小于1或大于总页数时,displayedDrivers会返回空数组,影响用户体验。

优化方案

方案1:保留静态生成,按页拆分静态页面

如果希望继续使用静态生成,可以结合getStaticPaths和getStaticProps,为每一页生成独立的静态页面:

// app/drivers/[page]/page.js
import { useRouter } from 'next/navigation'

export async function generateStaticParams() {
  // 先拉取总数据量,计算总页数
  const res = await fetch('http://ergast.com/api/f1/drivers.json?limit=1')
  const json = await res.json()
  const total = parseInt(json.MRData.total)
  const totalPages = Math.ceil(total / 50)

  // 生成所有页面参数
  return Array.from({ length: totalPages }, (_, i) => ({
    page: (i + 1).toString()
  }))
}

export default async function DriversPage({ params }) {
  const router = useRouter()
  const page = parseInt(params.page)
  const offset = (page - 1) * 50
  const res = await fetch(`http://ergast.com/api/f1/drivers.json?limit=50&offset=${offset}`)
  const json = await res.json()
  const drivers = json.MRData.DriverTable.Drivers
  const total = parseInt(json.MRData.total)
  const totalPages = Math.ceil(total / 50)

  const handleNextPage = () => {
    if (page < totalPages) {
      router.push(`/drivers/${page + 1}`)
    }
  }

  const handlePreviousPage = () => {
    if (page > 1) {
      router.push(`/drivers/${page - 1}`)
    }
  }

  return (
    <div>
      {/* 渲染车手列表 */}
      <button onClick={handlePreviousPage} disabled={page === 1}>上一页</button>
      <button onClick={handleNextPage} disabled={page === totalPages}>下一页</button>
    </div>
  )
}

方案2:客户端按需分页(更推荐)

如果数据可能频繁更新,或者不想承担全量静态生成的成本,可以把数据获取逻辑移到客户端,每次切换页面时才拉取对应页的数据:

'use client'
import { useState, useEffect } from 'react'

export default function Drivers() {
  const [page, setPage] = useState(1)
  const [drivers, setDrivers] = useState([])
  const [totalPages, setTotalPages] = useState(0)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    const fetchDrivers = async () => {
      setLoading(true)
      const offset = (page - 1) * 50
      const res = await fetch(`http://ergast.com/api/f1/drivers.json?limit=50&offset=${offset}`)
      const json = await res.json()
      setDrivers(json.MRData.DriverTable.Drivers)
      const total = parseInt(json.MRData.total)
      setTotalPages(Math.ceil(total / 50))
      setLoading(false)
    }

    fetchDrivers()
  }, [page])

  const handleNextPage = () => {
    if (page < totalPages) {
      setPage(page + 1)
    }
  }

  const handlePreviousPage = () => {
    if (page > 1) {
      setPage(page - 1)
    }
  }

  if (loading) return <div>加载中...</div>

  return (
    <div>
      {/* 渲染车手列表 */}
      <button onClick={handlePreviousPage} disabled={page === 1}>上一页</button>
      <button onClick={handleNextPage} disabled={page === totalPages}>下一页</button>
    </div>
  )
}

通用优化:边界处理

无论采用哪种方案,都必须添加分页边界校验:

  • 当page为1时,禁用「上一页」按钮
  • 当page等于总页数时,禁用「下一页」按钮
  • 避免page超出有效范围导致空数据或无效请求

内容的提问来源于stack exchange,提问作者SamePop20

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:44:57