Next.js v15.3.3博客部署Vercel时预渲染/post/1页面出现TypeError空值读取useState错误
看起来你遇到的这个预渲染错误,核心原因是服务器组件中直接使用了依赖React Hooks的客户端组件——从报错栈能明确看到,MDXRemote内部调用useState时,在服务器预渲染环境里React上下文为null,才抛出了这个异常。结合你的代码和Next.js App Router的规则,我给你梳理几个针对性的解决步骤:
1. 确保MdxContent是客户端组件
Next.js App Router中,默认创建的组件是服务器组件,不能使用任何React Hooks(比如useState、useEffect),而next-mdx-remote的MDXRemote内部依赖Hooks,必须在客户端组件中使用。
打开你的@/app/components/MdxContent.tsx,在文件最顶部添加'use client'指令:
// @/app/components/MdxContent.tsx 'use client'; // 这行必须放在文件第一行 import { MDXRemote } from 'next-mdx-remote/rsc'; // 根据你的next-mdx-remote版本调整导入路径 import type { MDXRemoteProps } from 'next-mdx-remote'; export function MdxContent({ source }: { source: MDXRemoteProps['source'] }) { return <MDXRemote source={source} />; }
这样MdxContent会被标记为客户端组件,在客户端环境执行,就能正常使用MDXRemote的Hooks逻辑了。
2. 检查next-mdx-remote版本兼容性
Next.js v15属于较新的版本,要确保你安装的next-mdx-remote版本和它兼容。建议你更新到最新稳定版:
npm install next-mdx-remote@latest # 或 yarn add next-mdx-remote@latest pnpm add next-mdx-remote@latest
如果是使用App Router的RSC(React Server Components)模式,务必使用next-mdx-remote/rsc的导入路径,而非旧的next-mdx-remote(那是Pages Router的用法)。
3. 验证getPostBySlug返回的数据完整性
报错发生在/post/1页面,有可能是该slug对应的post.content为null或格式错误,导致MDXRemote无法正常初始化。
在getPostBySlug函数里添加校验逻辑,确保返回的PostFull类型中content字段是有效的MDX编译内容(比如是经过serialize处理后的对象,而非原始字符串或null):
// @/lib/posts.ts import { serialize } from 'next-mdx-remote/serialize'; import matter from 'gray-matter'; import { readFile } from 'fs/promises'; import { join } from 'path'; export async function getPostBySlug(slug: string): Promise<PostFull> { // 读取MDX文件并解析frontmatter const postsDir = join(process.cwd(), 'posts'); const filePath = join(postsDir, `${slug}.mdx`); const rawContent = await readFile(filePath, 'utf8'); const { data, content } = matter(rawContent); // 序列化MDX内容,确保格式正确 const serializedContent = await serialize(content); return { slug, title: data.title, subtitle: data.subtitle, date: data.date, category: data.category, content: serializedContent, // 确保这里返回的是序列化后的有效对象 }; }
4. 预渲染参数的正确性校验
检查generateStaticParams返回的slug列表是否有效,避免生成不存在的/post/[slug]路径。比如可以在函数里过滤掉无效的文章:
// post/[slug]/page.tsx export async function generateStaticParams() { const posts = getAllPosts(); // 过滤掉没有slug或内容的无效文章 return posts.filter(post => post.slug && post.content).map((post) => ({ slug: post.slug, })); }
按照这几个步骤调整后,重新部署到Vercel应该就能解决预渲染错误了。如果还是有问题,可以尝试在本地执行npm run build复现错误,这样更容易排查本地和部署环境的差异。
内容来源于stack exchange

