如何在Next.js App Router中复用单次DB/API调用至generateMetadata与页面组件
解决Next.js 14 App Router中generateMetadata与组件重复查询数据库的问题
当然可以复用一次数据库查询的结果,核心思路是通过缓存机制让generateMetadata和组件共享同一份查询数据,以下是两种实用方案:
方案一:使用Next.js的unstable_cache(推荐,针对服务端缓存优化)
将数据库查询逻辑封装成带缓存的函数,这样两次调用都会命中缓存,仅执行一次数据库请求:
import { unstable_cache } from 'next/cache'; import prisma from '@/lib/prisma'; // 封装带缓存的博客查询函数 const getBlogBySlug = unstable_cache( async (slug: string) => { return prisma.blog.findUnique({ where: { slug }, include: { author: true } // 按需包含关联数据 }); }, ['blog-detail'], // 唯一缓存键,用于区分不同类型的缓存 { revalidate: 60 } // 缓存有效期(秒),可根据业务调整 ); // 在generateMetadata中调用缓存函数 export async function generateMetadata({ params }: { params: { slug: string } }) { const blog = await getBlogBySlug(params.slug); if (!blog) return { title: '博客不存在' }; return { title: blog.title, description: blog.excerpt }; } // 在页面组件中调用同一个缓存函数 export default async function BlogDetailPage({ params }: { params: { slug: string } }) { const blog = await getBlogBySlug(params.slug); if (!blog) return <div>博客不存在</div>; return ( <article> <h1>{blog.title}</h1> <div>{blog.content}</div> </article> ); }
unstable_cache是Next.js专为服务端渲染场景设计的缓存API,能确保相同参数的查询请求复用缓存结果,避免重复数据库调用。虽然标记为"unstable",但在Next.js 14中已经被广泛使用,后续大概率会稳定。
方案二:使用React的cache函数(通用React服务端缓存)
如果更倾向于使用原生React API,可以用React.cache包裹查询函数:
import { cache } from 'react'; import prisma from '@/lib/prisma'; // 用React.cache包裹查询函数 const getBlogBySlug = cache(async (slug: string) => { return prisma.blog.findUnique({ where: { slug } }); }); // 后续generateMetadata和组件中的调用逻辑与方案一完全一致
React.cache会在服务端渲染时缓存相同参数的函数调用结果,同样能实现数据复用。这种方式更贴合React生态,适合不需要精细控制缓存策略的场景。
注意事项
- 确保查询函数的参数是可序列化的(比如字符串、数字),这样缓存系统才能正确生成唯一缓存键。
- 若博客内容需要实时更新,可调整
revalidate时间(方案一),或使用缓存标签(tags参数)手动触发缓存刷新。 - 对于完全动态的内容,可结合增量静态再生(ISR)进一步优化性能。
内容的提问来源于stack exchange,提问作者masadamsahid
相关产品推荐
相关产品推荐

