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

Next.js上下文获取Token引发Hydration失败的解决方案咨询

解决Next.js Hydration失败:基于登录状态的Navbar条件渲染方案

问题根源

服务器渲染阶段无法获取客户端Cookies,导致服务器输出的Navbar UI(默认未登录状态)和客户端Hydrate时读取Cookies后渲染的UI(已登录/未登录)不一致,触发Error: Hydration failed because the initial UI does not match what was rendered on the server.。

可行解决方案

1. 客户端状态延迟初始化(修正useEffect用法)

核心思路是让服务器渲染一个中性占位UI,客户端Hydrate完成后再根据Cookies更新状态,确保前后UI匹配。

import { useContext, useEffect, useState } from 'react';
import { AuthContext } from '../contexts/AuthContext';

export default function Navbar() {
  const { cookies } = useContext(AuthContext);
  // 初始状态设为null,服务器渲染时返回空/占位
  const [isLoggedIn, setIsLoggedIn] = useState(null);

  useEffect(() => {
    // 仅在客户端执行,读取Cookies判断登录状态
    setIsLoggedIn(!!cookies.token && !!cookies.usuario);
  }, [cookies]);

  // 服务器渲染时返回空或骨架屏,避免Hydration不匹配
  if (isLoggedIn === null) {
    return null;
  }

  return (
    <nav>
      <ul>
        <li>首页</li>
        {isLoggedIn ? (
          <>
            <li>个人中心</li>
            <li>退出登录</li>
          </>
        ) : (
          <>
            <li>登录</li>
            <li>注册</li>
          </>
        )}
      </ul>
    </nav>
  );
}

2. 局部禁用SSR(精准拆分组件)

如果仅Navbar的某部分需要根据登录状态渲染,可将这部分抽离为单独组件,通过动态导入禁用SSR,避免整个Navbar放弃服务器渲染。

// NavAuthLinks.jsx(单独抽离的登录状态相关链接组件)
import { useContext } from 'react';
import { AuthContext } from '../contexts/AuthContext';

export default function NavAuthLinks() {
  const { cookies } = useContext(AuthContext);
  const isLoggedIn = !!cookies.token && !!cookies.usuario;

  return (
    <>
      {isLoggedIn ? (
        <>
          <li>个人中心</li>
          <li>退出登录</li>
        </>
      ) : (
        <>
          <li>登录</li>
          <li>注册</li>
        </>
      )}
    </>
  );
}

// Navbar.jsx(主组件)
import dynamic from 'next/dynamic';

// 动态导入并禁用SSR,加载时返回空占位
const NavAuthLinks = dynamic(() => import('./NavAuthLinks'), {
  ssr: false,
  loading: () => null,
});

export default function Navbar() {
  return (
    <nav>
      <ul>
        <li>首页</li>
        <NavAuthLinks />
      </ul>
    </nav>
  );
}

3. 使用useLayoutEffect同步客户端状态(可选)

如果需要在DOM更新前完成状态同步,可替换useEffect为useLayoutEffect,它会在客户端DOM渲染完成后、浏览器绘制前执行,适合对UI同步要求较高的场景:

import { useContext, useLayoutEffect, useState } from 'react';
import { AuthContext } from '../contexts/AuthContext';

export default function Navbar() {
  const { cookies } = useContext(AuthContext);
  const [isLoggedIn, setIsLoggedIn] = useState(null);

  useLayoutEffect(() => {
    setIsLoggedIn(!!cookies.token && !!cookies.usuario);
  }, [cookies]);

  if (isLoggedIn === null) {
    return null;
  }

  // 后续渲染逻辑同方案1
}

注意事项

  • 禁止在服务器渲染阶段直接访问客户端Cookies:服务器环境没有浏览器Cookies,任何依赖Cookies的判断都要放到客户端执行。
  • 初始状态必须中性:不能将isLoggedIn初始化为false或true,否则服务器渲染的UI会和客户端Hydrate后的UI不一致,触发错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 18:22:39