NextJS动态路由参数变化后getStaticProps未触发如何解决?
问题根源
你当前使用的是Next.js Pages Router的纯静态生成(SSG)模式,getStaticProps仅在项目构建阶段执行一次,同个动态路由模板(/pages/[category]/index.tsx)的客户端路由跳转时,Next.js会复用已加载的页面组件实例,不会重新触发getStaticProps拉取新数据,因此只有刷新页面时才会请求服务器拿到对应分类的静态页面数据。
解决方案
方案1:替换为getServerSideProps(最推荐,改造成本最低)
直接将静态生成改为服务端渲染,每次请求(包括客户端路由跳转)都会重新执行服务端逻辑拉取对应分类的数据,完全符合你的需求。
- 删除现有
getStaticPaths代码,getServerSideProps不需要预先生成路径 - 将
getStaticProps替换为如下代码:
export const getServerSideProps: GetServerSideProps = async (context) => { const category = context.params?.category as string || ""; const productsData = await getPaginatedProducts(1, category); const envPag = process.env.pagination || '0'; const totalPages = Math.ceil(productsData.total / parseInt(envPag)); return { props: { products: productsData.items, totalPages, currentPage: 1 }, } }
- 优点:代码改动量极小,不需要调整组件逻辑,数据永远和服务端同步
- 缺点:响应速度比纯SSG稍慢,对分类页这类场景几乎感知不到差异
方案2:保留SSG,监听路由变化手动拉取数据
如果需要保留SSG的首屏加载速度优势,可以在组件内监听分类参数变化,手动触发数据拉取更新本地状态。
- 给
getStaticProps添加revalidate配置开启增量静态再生,保证构建后的数据可更新:
export const getStaticProps: GetStaticProps = async (context) => { const category = context.params?.category || ""; const productsData = await getPaginatedProducts(1, category); const envPag = process.env.pagination || '0'; const totalPages = Math.ceil(productsData.total / parseInt(envPag)); return { props: { products: productsData.items, totalPages, currentPage: 1 }, revalidate: 60 // 单位为秒,可根据业务需求调整缓存时间 } }
- 调整页面组件逻辑,添加状态管理和路由监听:
// 新增导入 import { useState, useEffect } from 'react' export default function ProductsIndex(props: ProductsIndexProps) { const router = useRouter(); // 新增本地状态存储页面数据 const [products, setProducts] = useState<ProductItemModel[]>(props.products); const [totalPages, setTotalPages] = useState(props.totalPages); const [currentPage, setCurrentPage] = useState(props.currentPage); // 监听分类参数变化,拉取对应分类数据 useEffect(() => { if (!router.isReady) return; const category = router.query.category as string || ""; const fetchCategoryData = async () => { const productsData = await getPaginatedProducts(1, category); // 注意前端访问的环境变量需要添加NEXT_PUBLIC_前缀 const envPag = process.env.NEXT_PUBLIC_pagination || '0'; const total = Math.ceil(productsData.total / parseInt(envPag)); setProducts(productsData.items); setTotalPages(total); setCurrentPage(1); } fetchCategoryData(); }, [router.query.category, router.isReady]) return ( <div> <div className={styles.title_section}> <h2 className={styles.title}>Results for all items</h2> </div> <div className={styles.list_container}> <section className={styles.list_sidebar}></section> <ProductList products={products} category={asString(router.query.category || "") || ""} currentPage={currentPage} totalPages={totalPages} /> </div> </div> ); }
- 优点:首屏保留SSG的高性能,客户端跳转体验流畅
- 缺点:需要额外编写状态逻辑,若
getPaginatedProducts依赖仅服务端可访问的Contentful密钥,需要额外封装前端可调用的接口层
方案3:跳转时强制刷新页面(不推荐)
在分类跳转的链接上使用原生页面跳转代替Next.js客户端路由,每次跳转都会重新请求页面资源拉取对应数据,但会丢失单页应用的流畅跳转体验,仅适合临时调试使用。
内容的提问来源于stack exchange,提问作者Daniel Molnar
相关产品推荐
相关产品推荐

