Next.js 13如何在SSG页面中同时使用searchParams与路由参数
问题
我正在使用Next.js App Router搭建博客,现有路由为/blogs/category/[name],该页面是采用generateStaticParams()的SSG页面,构建时会预渲染所有分类下的博客,原有代码如下:
export default async function Blogs({ params: { name } } : { params: { name: string } }) { const blogs = await fetchBlogs({ category: decodeURIComponent(name) }) const blogCount = await fetchBlogCount({ category: name }) return <>Rest of the component......</> } export async function generateStaticParams() { const categories = await fetchCategories() return categories.map(category => ({ name: category })) }
目前该SSG页面运行正常,但现在需要在分类内实现博客搜索功能,要用到searchParams。需求是:无searchParams时展示预渲染页面,有searchParams时仅在服务器端运行,同时保留SSG特性。
我尝试了以下代码,但出现错误Error: Dynamic server usage: searchParams.search,虽然添加export const dynamic = 'force-dynamic'可以解决,但不想放弃SSG特性:
export default async function Blogs({ params: { name }, searchParams: { search } }: { params: { name: string }, searchParams: { search?: string } }) { const blogs = await fetchBlogs({ category: decodeURIComponent(name), search }) const blogCount = await fetchBlogCount({ category: name }) return <>Rest of the component......</> }
请问如何实现这一需求?
解决方案
核心思路是把搜索逻辑从页面组件中剥离,改用Server Component的动态数据获取逻辑,同时保留静态预渲染的基础页面,具体实现如下:
1. 修改主页面组件(保留SSG特性)
// app/blogs/category/[name]/page.tsx import SearchResults from './SearchResults'; export default async function Blogs({ params: { name }, searchParams }: { params: { name: string }, searchParams: { search?: string } }) { // 无搜索参数时,使用预渲染的静态数据 const staticBlogs = await fetchBlogs({ category: decodeURIComponent(name) }); const blogCount = await fetchBlogCount({ category: name }); // 存在搜索参数时,渲染动态搜索结果组件 if (searchParams?.search) { return <SearchResults category={name} search={searchParams.search} />; } // 无搜索参数时,返回预渲染的静态页面内容 return <> {/* 原有静态页面的UI结构 */} {staticBlogs.map(blog => ( // 渲染博客列表项 ))} </>; } export async function generateStaticParams() { const categories = await fetchCategories(); return categories.map(category => ({ name: category })); } // 强制页面优先使用静态预渲染模式 export const dynamic = 'force-static';
2. 创建独立的搜索结果组件(Server Component)
// app/blogs/category/[name]/SearchResults.tsx export default async function SearchResults({ category, search }: { category: string, search: string }) { // 仅在有搜索参数时,动态获取过滤后的博客数据 const blogs = await fetchBlogs({ category: decodeURIComponent(category), search }); return <> {/* 搜索结果的UI结构 */} {blogs.map(blog => ( // 渲染搜索到的博客项 ))} </>; }
原理说明
export const dynamic = 'force-static'强制页面在构建阶段预渲染所有分类的静态版本,避免因为searchParams的存在触发自动动态模式。- 搜索逻辑被隔离到独立的Server Component中,只有当存在
search参数时才会加载该组件,此时组件会在服务器端动态执行数据获取,完全不影响主页面的静态预渲染特性。 - 无搜索参数时,用户访问的是构建时生成的静态HTML;有搜索参数时,服务器会实时生成搜索结果返回。
内容的提问来源于stack exchange,提问作者Hef
相关产品推荐
相关产品推荐

