Next.js 13 App Router:如何避免generateMetadata重复处理?
解决Next.js 13 App Router中generateMetadata重复处理逻辑的问题
在App Router模式下,generateMetadata和页面组件是独立执行的,但我们可以通过封装带缓存的共享逻辑来避免重复处理,具体方案如下:
1. 提取共享逻辑到缓存函数
把API请求、html_title/html_description生成等重复逻辑,封装到一个用React.cache包裹的异步函数中。React.cache会在同一次请求生命周期内缓存函数结果,确保相同参数下只执行一次处理逻辑。
// lib/article.js import { cache } from 'react'; export const getArticleAndMeta = cache(async (slug) => { // 调用API获取文章原始数据 const res = await fetch(`/api/articles/${slug}`, { next: { revalidate: 60 } }); const rawArticle = await res.json(); // 处理生成需要复用的元数据和其他计算值 const html_title = rawArticle.title ? `${rawArticle.title} | 站点名称` : '站点名称'; const html_description = rawArticle.excerpt || '默认站点描述'; // 这里可以添加其他重复处理的逻辑,比如标签格式化、内容预处理等 return { article: rawArticle, meta: { title: html_title, description: html_description } }; });
2. 在generateMetadata和页面组件中复用该函数
在page.js中,让generateMetadata和页面组件都调用这个缓存后的函数,实现数据和处理逻辑的共享:
// app/articles/[slug]/page.js import { getArticleAndMeta } from '@/lib/article'; import ArticleDetail from './ArticleDetail'; export async function generateMetadata({ params }) { const { meta } = await getArticleAndMeta(params.slug); return meta; } export default async function ArticlePage({ params }) { const { article, meta } = await getArticleAndMeta(params.slug); // 这里可以把处理好的数据传给组件,或用于其他页面逻辑 return <ArticleDetail article={article} pageTitle={meta.title} />; }
3. 可选:使用Next.js持久化缓存
如果需要跨请求缓存处理结果(比如同slug的多次访问),可以替换React.cache为Next.js的unstable_cache(注意该API目前标记为不稳定,后续可能调整):
// lib/article.js import { unstable_cache } from 'next/cache'; export const getArticleAndMeta = unstable_cache( async (slug) => { // 同上面的API请求和处理逻辑 }, ['article-meta', slug], // 缓存键,确保不同slug有独立缓存 { revalidate: 3600 } // 缓存有效期,单位秒 );
这样处理后,无论是API请求还是后续的元数据生成逻辑,都只会执行一次,彻底消除重复处理带来的性能损耗。
内容的提问来源于stack exchange,提问作者Tony Vu
相关产品推荐
相关产品推荐

