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

客户端组件条件渲染触发Hydration错误求助

Next.js 客户端组件基于Cookie条件渲染触发Hydration失败的解决办法

当在Next.js客户端组件中直接读取Cookie值并渲染时,刷新页面会抛出以下错误:

react-dom.development.js:7076 Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.

问题根源

你误以为服务器无法感知Cookie状态,但实际上Next.js的SSR机制会在服务器端渲染所有组件(包括客户端组件)的初始HTML。服务器能通过请求头拿到Cookie,所以渲染客户端组件时会使用Cookie值生成对应内容;而客户端在hydration阶段(首次渲染)会对比服务器生成的HTML和自己渲染的DOM,一旦两者不一致就会触发错误——哪怕你觉得这种差异是合理的,Next.js的hydration机制也会严格要求两端初始渲染结果一致。

解决方案

方案1:延迟客户端Cookie读取(避免hydration不匹配)

通过useState设置初始默认值,在useEffect中延迟读取Cookie,确保客户端hydration完成后再更新UI。这样服务器端渲染的初始HTML和客户端首次渲染结果一致,后续再更新为正确的Cookie值。

修改后的客户端组件代码:

"use client";
import { useState, useEffect } from "react";
import { getCookie } from "cookies-next";

export default function ClientComponent() {
  const [version, setVersion] = useState(null);

  useEffect(() => {
    // 仅在客户端hydration完成后执行Cookie读取
    const cookieVal = getCookie("version");
    setVersion(cookieVal);
  }, []);

  return (
    <p className="text-black">
      The cookies is currently set to: {version ?? "undefined"}
    </p>
  );
}

如果不想依赖第三方库,也可以直接用原生方式读取Cookie:

"use client";
import { useState, useEffect } from "react";

export default function ClientComponent() {
  const [version, setVersion] = useState(null);

  useEffect(() => {
    const getCookie = (name) => {
      return document.cookie.split('; ')
        .find(row => row.startsWith(`${name}=`))
        ?.split('=')[1];
    };
    setVersion(getCookie("version"));
  }, []);

  return (
    <p className="text-black">
      The cookies is currently set to: {version ?? "undefined"}
    </p>
  );
}

方案2:服务器传递Cookie值给客户端组件(避免UI闪烁)

如果不想出现客户端hydration后UI更新的闪烁,可以让服务器组件先读取Cookie,再将值传递给客户端组件。这样服务器端渲染的HTML已经包含正确的Cookie值,客户端hydration时初始渲染和服务器一致,后续再同步客户端Cookie变化。

修改首页(服务器组件)代码:

import { cookies } from "next/headers";
import ClientComponent from "@/components/client-component";

export default function Home() {
  const cookieStore = cookies();
  const serverVersion = cookieStore.get("version")?.value;

  return (
    <main className="p-24">
      <form
        action={async function() {
          "use server";
          const cookieStore = cookies();
          cookieStore.set("version", "a");
        }}
      >
        <button type="submit">Set version to "a"</button>
      </form>

      <form
        action={async function() {
          "use server";
          const cookieStore = cookies();
          cookieStore.set("version", "b");
        }}
      >
        <button type="submit">Set version to "b"</button>
      </form>
      {/* 传递服务器读取的Cookie值 */}
      <ClientComponent initialVersion={serverVersion} />
    </main>
  );
}

修改客户端组件:

"use client";
import { useState, useEffect } from "react";
import { getCookie } from "cookies-next";

export default function ClientComponent({ initialVersion }) {
  const [version, setVersion] = useState(initialVersion);

  useEffect(() => {
    // 监听Cookie变化,确保客户端值始终最新
    const updateCookie = () => {
      const cookieVal = getCookie("version");
      setVersion(cookieVal);
    };

    // 初始同步一次
    updateCookie();

    // 定时检查Cookie变化(可根据需求调整间隔)
    const interval = setInterval(updateCookie, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
    <p className="text-black">
      The cookies is currently set to: {version ?? "undefined"}
    </p>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:52:10