You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13 App目录下使用Link组件出现Hydration失败问题求助

Next.js 13 App目录下Link组件Hydration失败排查

问题概述

在Next.js 13 App目录结构项目中,使用Link组件时触发Hydration失败错误,提示客户端初始UI与服务端生成的HTML不匹配。移除Link组件后错误消失,但改用a标签或静态href仍无法解决,不确定动态href是否可在Link组件中使用。

浏览器报错信息

Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Expected server HTML to contain a matching a tag in div

代码示例

const Page = async () => {
  const blogs = await fetchBlog();

  return (
    <div className="w-full md:w-1/3 min-h-screen mx-auto">
      <h1 className="text-2xl font-bold text-black mt-5">My Writings:</h1>
      <div className="mt-5 p-6 flex text-black justify-center">
      <div className="">
      <div>
        {blogs.map((blog) => (
          <div key={blog.id}>
            <div className="mt-4">
              <Image
                src={blog.acf.image.url}
                alt={blog.acf.image.alt}
                width={300}
                height={300}
                style={{ maxWidth: "300px", maxHeight: "300px" }}
              />
            </div>
            <div className="font-bold mt-2">{blog.acf.title}</div>
            <div className="mb-5">
              {blog.acf.description.length > 300
                ? <div dangerouslySetInnerHTML={{ __html: blog.acf.description.substring(0, 200) }} /> 
                : <div dangerouslySetInnerHTML={{ __html: blog.acf.description }} />}
                <div>
                <Link className="font-bold text-black" href={`/blogs/${blog.id}`}>Read More...</Link>
                </div>
            </div>
          </div>
        ))}
      </div>
    </div>
      </div>
    </div>
  );
};

问题排查与修复方案

Next.js 13 App目录下的Link组件支持动态href,但以下几点可能导致Hydration不匹配:

  1. blog.id的类型不一致
    服务端渲染时fetchBlog()返回的blog.id如果是数字类型,客户端渲染时可能被转为字符串(或反之),导致生成的href路径不一致(比如/blogs/123 vs /blogs/"123"),触发UI不匹配。
    修复:强制将blog.id转为字符串,确保路径一致:

    <Link className="font-bold text-black" href={`/blogs/${String(blog.id)}`}>Read More...</Link>
    
  2. 服务端与客户端数据不一致
    若fetchBlog()在服务端和客户端返回的blogs数据存在差异(比如服务端有额外字段、id值不同),会导致渲染的Link组件数量或路径不一致。
    修复:验证fetchBlog()的实现,确保SSR和CSR时返回完全相同的数据,比如禁用客户端缓存、统一数据格式。

  3. dangerouslySetInnerHTML的干扰
    blog.acf.description中的HTML内容在服务端和客户端解析后可能存在结构差异,间接影响周围Link组件的渲染匹配。
    修复:

    • 如果不需要保留HTML格式,改用纯文本截取:blog.acf.description.substring(0, 200)
    • 若必须保留HTML,确保截取后的片段是完整的(比如避免截断标签),或者使用useEffect在客户端挂载后再渲染该部分内容,隔离服务端渲染差异。
  4. 尝试添加passHref属性
    虽然App目录下Link默认不需要passHref,但某些场景下显式添加可解决标签匹配问题:

    <Link passHref className="font-bold text-black" href={`/blogs/${String(blog.id)}`}>Read More...</Link>
    

内容的提问来源于stack exchange,提问作者Karl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:37:05