如何为基于本地无分页JSON的NextJS应用实现URL同步分页
基于本地JSON的NextJS分页实现方案(URL同步版)
核心思路
利用NextJS的路由参数管控页码,结合slice处理本地数据,确保URL随页码实时变化,支持页面刷新、前进后退时保留分页状态。
具体实现步骤
1. 加载本地JSON数据
假设JSON文件存放在data/products.json,先在组件中读取数据:
import productsData from '../data/products.json'; const products = Object.values(productsData);
2. App Router(NextJS 13+)实现方案
'use client'; import { useSearchParams, useRouter } from 'next/navigation'; import Product from './Product'; export default function ProductsPage() { const searchParams = useSearchParams(); const router = useRouter(); const itemsPerPage = 10; // 获取当前页码,默认显示第1页 const currentPage = parseInt(searchParams.get('page')) || 1; // 计算当前页数据的起始/结束索引 const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const currentProducts = products.slice(startIndex, endIndex); // 计算总页数 const totalPages = Math.ceil(products.length / itemsPerPage); // 页码切换逻辑 const goToPage = (page) => { if (page < 1 || page > totalPages) return; const params = new URLSearchParams(searchParams); params.set('page', page); router.push(`/?${params.toString()}`); }; return ( <div> <div className="products-grid"> {currentProducts.map((item) => ( <Product {...item} key={item.id} /> {/* 优先用产品唯一ID作为key,避免index引发的渲染问题 */} ))} </div> {/* 分页控件 */} <div className="pagination"> <button onClick={() => goToPage(currentPage - 1)} disabled={currentPage === 1}> 上一页 </button> {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => ( <button key={page} onClick={() => goToPage(page)} style={{ backgroundColor: currentPage === page ? '#0070f3' : 'transparent', color: currentPage === page ? '#fff' : '#000' }} > {page} </button> ))} <button onClick={() => goToPage(currentPage + 1)} disabled={currentPage === totalPages}> 下一页 </button> </div> </div> ); }
3. Pages Router(旧版)兼容方案
import { useRouter } from 'next/router'; import Product from './Product'; import productsData from '../data/products.json'; export default function ProductsPage() { const router = useRouter(); const { page = 1 } = router.query; const products = Object.values(productsData); const itemsPerPage = 10; const currentPage = parseInt(page); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const currentProducts = products.slice(startIndex, endIndex); const totalPages = Math.ceil(products.length / itemsPerPage); const goToPage = (targetPage) => { if (targetPage < 1 || targetPage > totalPages) return; router.push({ query: { ...router.query, page: targetPage } }); }; // 组件返回结构与App Router版一致,此处省略重复代码 }
关键注意事项
- URL同步:通过
?page=X搜索参数记录页码,刷新页面不会丢失当前页状态,完全符合NextJS路由特性。 - Key优化:避免用
index作为组件key,优先使用产品的唯一标识(如item.id),减少不必要的组件重渲染。 - 边界校验:添加页码上下限判断,防止非法页码导致数据异常。
- 静态生成适配:若数据无需频繁更新,可通过
getStaticPaths预生成所有分页页面,结合getStaticProps传递对应页码数据:
// Pages Router 静态生成示例 export async function getStaticPaths() { const products = Object.values(productsData); const itemsPerPage = 10; const totalPages = Math.ceil(products.length / itemsPerPage); const paths = Array.from({ length: totalPages }, (_, i) => ({ params: { page: (i + 1).toString() } })); return { paths, fallback: false }; } export async function getStaticProps({ params }) { const page = parseInt(params.page); const itemsPerPage = 10; const startIndex = (page - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const currentProducts = Object.values(productsData).slice(startIndex, endIndex); return { props: { products: currentProducts, currentPage: page, totalPages: Math.ceil(productsData.length / itemsPerPage) } }; }
内容的提问来源于stack exchange,提问作者Yakushi
相关产品推荐
相关产品推荐

