Next.js 14动态元数据不显示:子目录布局元数据未生效
解决Next.js app目录中子布局动态metadata不生效的问题
你的问题出在**generateMetadata里调用了React Hook**,这违反了Next.js的规则,导致动态metadata生成失败,系统自动 fallback 使用根布局的静态metadata。
核心问题分析
Next.js的generateMetadata是Server Component的顶层异步函数,不能调用任何React Hooks(比如你写的useArticle)。Hooks只能在React组件的渲染上下文里使用,顶层函数不在这个范围内,一旦调用会直接抛出错误,Next.js就会自动使用父级路由(根布局)的metadata。
另外你写的useArticle本质是把数据获取逻辑包裹成了Hook,但这种场景根本不需要Hook,直接用普通的服务端函数即可。
修复步骤
1. 重构数据获取逻辑,去掉Hook包裹
把fetchArticle改成独立的服务端函数,比如新建lib/article.ts文件:
// lib/article.ts export async function fetchArticle(slug: string) { const api = process.env.NODE_ENV === "production" ? `https://${process.env.PRODUCTION_URL}/api/articles?query=` : "http://localhost:3000/api/articles?query="; const response = await fetch(`${api}${slug}`, { next: { revalidate: 60 }, }); // 处理请求失败的情况 if (!response.ok) { throw new Error(`获取文章失败:${response.status}`); } const article = await response.json(); return Array.isArray(article) && article.length > 0 ? article[0] : null; }
2. 修改子布局的generateMetadata,直接调用独立函数
修改app/article/[slug]/layout.tsx的代码,去掉对useArticle的调用:
// app/article/[slug]/layout.tsx import type { Metadata } from "next"; import { fetchArticle } from "@/lib/article"; // 根据你的项目路径调整导入 import type { ArticleInterface } from "@/types/article"; // 导入你的类型定义 export const generateMetadata = async ({ params: { slug }, }: { params: { slug: string }; }): Promise<Metadata> => { const article = (await fetchArticle(slug)) as ArticleInterface; // 处理文章不存在的情况 if (!article) { return { title: "文章不存在", }; } return { title: article.title, }; }; export default function Layout({ children }: { children: React.ReactNode }) { return <> {children} </>; }
额外注意事项
- 确保环境变量
PRODUCTION_URL在生产环境中已正确配置,否则API地址会出错。 - 子布局的文件名必须是
layout.tsx(或.jsx),Next.js才能识别它作为该路由段的布局文件。 - 建议对
fetch请求增加错误处理,避免因API请求失败导致整个页面metadata生成失败。
内容的提问来源于stack exchange,提问作者Sarotobi
相关产品推荐
相关产品推荐

