Next.js使用getServerSideProps实现表格分页API动态传参
实现方案
首先明确核心问题:你当前把接口请求逻辑全写在getServerSideProps里,这个函数只会在页面首次服务端渲染、服务端路由跳转时触发,客户端点击按钮不会重新执行它,所以写死的page=1不会动态变化。
关于是否需要useEffect的说明
不需要专门写useEffect在客户端发请求。如果硬要把分页请求挪到客户端做,确实可以用useEffect监听页码状态变化重新拉数据,但这种方案会丢失SSR首屏直出的优势,白屏时间更长,而且你已经在getServerSideProps里写好的数据过滤、字段格式化逻辑要在客户端重复写一遍,冗余度高,不推荐。
最合适的方案是把页码同步到路由query参数中,让getServerSideProps跟着路由参数的变化自动拉取对应页的数据,全程复用已有的服务端数据处理逻辑,不需要额外写客户端请求代码。
具体修改步骤
1. 改造getServerSideProps支持动态页码
把原来写死的page=1改成从路由参数里读取动态值,同时加参数合法性校验,避免非法页码参数导致报错:
export async function getServerSideProps(context) { const { params, res, query } = context const { tabla } = params // 从query取页码,默认值为1,转成数字类型 const currentPage = Number(query.page) || 1 const pageSize = 25 // 替换固定page参数为动态值 const apiResponse = await fetch(`${process.env.NEXT_PUBLIC_API_URL}admin/users/signup-status?page=${currentPage}&page_size=${pageSize}`) if (apiResponse.ok) { let responseData = await apiResponse.json() const mapped = responseData.results.map(user => { return { ...user, wait_time: parseInt(user.wait_time.split(' ')[0]) || 0 } }) let data = mapped // 原有数据过滤、字段处理逻辑完全保留 if (tabla === 'cartera') { data = mapped.map(user => { const dataUser = { ...user } delete dataUser.wait_time return dataUser }) } else { data = mapped.filter(user => { if (tabla === 'primera') { return user.status === 'revision' } if (tabla === 'segunda') { return user.status === 'segunda' } if (tabla === 'seguimiento') { return user.status === 'seguimiento' || user.status === 'caducado' } }) if (tabla === 'primera') { data = data.map(user => { const dataUser = { ...user } delete dataUser.comments return dataUser }) } } // 计算总页数,做页码合法性校验 const totalPages = Math.ceil(responseData.count / pageSize) if (currentPage < 1 || currentPage > totalPages) { res.writeHead(302, { location: `/${tabla}?page=1` }).end() return { props: {} } } const pages = Array.from({ length: totalPages }, (_, i) => i + 1) // 把当前页码、总页数列表传给组件 return { props: { data, pages, currentPage } } } if (res) { res.writeHead(301, { location: '/404' }).end() } }
2. 改造前端组件,给分页按钮加跳转逻辑
删掉原来没用的本地pageIndex状态,直接用服务端传回来的当前页码,点击按钮时通过路由跳转修改page参数即可,路由变化后会自动触发getServerSideProps拉取新页数据:
const UnderWriting = (props) => { // 从props解构服务端传回的分页数据 const { data, currentPage, pages } = props const [dataToShow, setDataToShow] = useState(data) const [title, setTitle] = useState('') const router = useRouter() const { tabla } = router.query // 分页跳转方法 const handlePageChange = (targetPage) => { router.push({ pathname: router.pathname, query: { ...router.query, page: targetPage } }) } useEffect(() => { switch (tabla) { case 'primera': { setTitle('Primera revision de UW') break } case 'segunda': { setTitle('Segunda revision de UW') break } case 'seguimiento': { setTitle('En Seguimiento UW') break } case 'cartera': { setTitle('Cartera de UW') break } } setDataToShow(data) }, [tabla, data]) const totalPages = pages.length return ( <Box> <Box> <Box color='#96A0AA' border='1px solid #DFE6EE' boxShadow='lg' overflow='hidden' rounded='lg'> <TablesData data={dataToShow} /> </Box> <Center> <HStack mt={5} mb={5} > <Button onClick={() => handlePageChange(currentPage - 1)} isDisabled={currentPage === 1} > Anterior </Button> <Button onClick={() => handlePageChange(currentPage + 1)} isDisabled={currentPage === totalPages} > Siguiente </Button> </HStack> </Center> </Box> </Box> ); }
方案优势
- 完全适配Next.js Pages Router的SSR设计,首屏直出速度快,不损失SEO能力
- 页码存在URL参数中,用户刷新页面、分享链接、点击浏览器前进后退都能准确定位到对应页码,不会重置到第一页
- 所有数据处理逻辑都在服务端完成,不需要在客户端重复写接口请求、数据格式化代码,维护成本低
- 分页按钮自带禁用状态逻辑,边界情况处理完善,不会出现请求小于1或者超出总页数的无效接口
内容的提问来源于stack exchange,提问作者Federico Lombardozzi
相关产品推荐
相关产品推荐

