Next.js 13 App Router中正确使用JSON-LD结构化数据的方法
解决Next.js 13 App Router中next-seo的useContext错误及结构化数据添加方法
一、修复next-seo的报错问题
你遇到的Cannot read properties of null (reading 'useContext')错误,核心原因是NextSeo属于客户端组件,而App Router的RootLayout默认是服务器组件,不能直接在服务器组件中渲染客户端组件,且useContext仅能在客户端组件环境中运行。
解决步骤:
- 创建单独的客户端组件文件,比如
app/components/NextSeoClient.js:
'use client'; // 必须添加该指令标记为客户端组件 import { NextSeo } from 'next-seo'; export default function NextSeoClient() { return ( <NextSeo useAppDir={true} // 在这里配置你的SEO及结构化数据 structuredData={{ "@context": "https://schema.org", "@type": "Website", "name": "你的网站名称", "description": "你的网站描述" }} /> ); }
- 在RootLayout中导入并使用该客户端组件:
import NextSeoClient from './components/NextSeoClient'; import { inter } from './fonts'; export default function RootLayout({ children }) { return ( <html lang="en"> <head> {/* 此处放置服务器端可处理的元数据,如title、基础meta标签等 */} </head> <body className={inter.className}> <NextSeoClient /> {/* 客户端组件需放在body内 */} <Navbar /> {children} <Analytics /> </body> </html> ); }
二、无需依赖next-seo,直接添加结构化数据的方法
如果不想使用next-seo包,也可以通过以下两种原生方式在App Router中添加结构化数据:
方式1:通过metadata导出(服务器端生成)
在app/layout.js中导出metadata,直接注入结构化数据脚本:
import { inter } from './fonts'; export const metadata = { title: '你的网站标题', description: '你的网站描述', other: { script: [ { type: 'application/ld+json', dangerouslySetInnerHTML: { __html: JSON.stringify({ "@context": "https://schema.org", "@type": "Website", "name": "你的网站名称", "description": "你的网站描述", "url": "https://你的域名.com" }) } } ] } }; export default function RootLayout({ children }) { return ( <html lang="en"> <body className={inter.className}> <Navbar /> {children} <Analytics /> </body> </html> ); }
方式2:客户端组件动态生成(适配动态数据场景)
如果结构化数据需要依赖页面动态数据,可创建客户端组件实现:
'use client'; import { useEffect } from 'react'; export default function StructuredData({ data }) { useEffect(() => { const script = document.createElement('script'); script.type = 'application/ld+json'; script.textContent = JSON.stringify({ "@context": "https://schema.org", "@type": "Article", "headline": data.title, "description": data.description, "author": { "@type": "Person", "name": "作者名称" } }); document.head.appendChild(script); return () => { document.head.removeChild(script); }; }, [data]); return null; }
之后在页面或layout中导入该组件,传入对应动态数据即可。
内容的提问来源于stack exchange,提问作者Warrior
相关产品推荐
相关产品推荐

