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

NextJS项目添加shadcn导航栏时出现Hydration错误求助

修复Next.js中ShadCN导航栏的Hydration错误

核心问题分析

Hydration错误本质是服务器渲染的DOM与客户端初始化后的DOM结构不匹配,你的代码存在几个关键问题:

  1. 嵌套的Link组件:Next.js不允许Link嵌套,会导致两端解析的DOM结构不一致
  2. NavigationMenu使用不规范:直接在NavigationMenuItem内使用Next.js的Link,不符合组件规范
  3. 移动端logo放置位置不合理:嵌套在Sheet内部可能引发渲染结构差异

具体修复步骤

1. 移除嵌套的Link组件

原代码中嵌套Link是错误写法,修改为单一层级:

// 错误写法
<Link className="mr-2 mb-1 items-center lg:flex" href="#">
  <Link href={"/"}>...</Link>
</Link>

// 修改后
<Link href="/" className="mr-2 mb-1 items-center lg:flex">
  <Image
    src="/logo-makak-horB.png"
    className="lg:flex hidden h-auto"
    height={20}
    width={180}
    alt="logo makak black horizontal"
  />
  <span className="sr-only">Acme Inc</span>
</Link>

2. 规范NavigationMenu的使用

NavigationMenuItem内部必须用NavigationMenuLink包裹Next.js的Link,确保状态一致:

// 错误写法
<NavigationMenuItem>
  <Link href="#" className="...">Services</Link>
</NavigationMenuItem>

// 修改后
<NavigationMenuItem>
  <NavigationMenuLink asChild>
    <Link
      href="#"
      className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-gray-100/50 data-[state=open]:bg-gray-100/50 "
    >
      Services
    </Link>
  </NavigationMenuLink>
</NavigationMenuItem>

将所有直接放在NavigationMenuItem中的Link都按此方式修改。

3. 调整移动端logo位置

将移动端logo从Sheet内部移到外部,避免服务器端渲染时的结构冲突:

// 移到Sheet组件外部
<Image
  className="lg:hidden"
  src="/logo-makak-horB.png"
  height={20}
  width={180}
  alt="logo makak black horizontal"
/>

<Sheet>
  {/* 移除Sheet内部的重复logo代码 */}
  <div className="lg:hidden flex justify-between w-full">...</div>
  <SheetContent>...</SheetContent>
</Sheet>

4. 可选:用Suspense缓冲客户端渲染

如果上述修改后仍有错误,可在使用Navbar的地方用Suspense包裹,给客户端渲染留缓冲:

import { Suspense } from 'react';
import { Navbar } from '@/components/Navbar';

function Layout({ children }) {
  return (
    <>
      <Suspense fallback={<div className="h-20 w-full bg-stone-100"></div>}>
        <Navbar />
      </Suspense>
      <main>{children}</main>
    </>
  );
}

修复后的完整Navbar代码

"use client";
import { Sheet, SheetTrigger, SheetContent } from "@/components/ui/sheet";
import Link from "next/link";
import { Button } from "./ui/button";
import Image from "next/image";
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu";

export function Navbar() {
  return (
    <div className="fixed top-0 w-full z-50">
      <header className="flex h-20 shadow-xl opacity-95 border-b-2 z-50 border-orange-400 bg-stone-100 shrink-0 items-center px-4 md:px-20">
        {/* 移动端logo移至Sheet外部 */}
        <Image
          className="lg:hidden"
          src="/logo-makak-horB.png"
          height={20}
          width={180}
          alt="logo makak black horizontal"
        />
        
        <Sheet>
          <div className="lg:hidden flex justify-between w-full">
            <Button asChild className="lg:hidden" size="icon" variant="outline">
              <SheetTrigger className="flex">
                <MenuIcon className="h-6 w-6" />
                <span className="sr-only">Toggle navigation menu</span>
              </SheetTrigger>
            </Button>
          </div>

          <SheetContent side="left">
            <Link className="mr-6 lg:hidden flex" href="/">
              <Image
                src="/logo-makak-horB.png"
                height={20}
                width={180}
                alt="logo makak black"
              />
              <span className="sr-only">Acme Inc</span>
            </Link>
            <div className="grid gap-2 py-6">
              <Link
                className="flex w-full items-center py-2 text-lg font-semibold"
                href="/"
              >
                Home
              </Link>
              <Link
                className="flex w-full items-center py-2 text-lg font-semibold"
                href="/about"
              >
                About
              </Link>
              <Link
                className="flex w-full items-center py-2 text-lg font-semibold"
                href="/services"
              >
                Services
              </Link>
              <Link
                className="flex w-full items-center py-2 text-lg font-semibold"
                href="/contact"
              >
                Contact
              </Link>
            </div>
          </SheetContent>
        </Sheet>

        {/* 修复嵌套Link */}
        <Link href="/" className="mr-2 mb-1 items-center lg:flex">
          <Image
            src="/logo-makak-horB.png"
            className="lg:flex hidden h-auto"
            height={20}
            width={180}
            alt="logo makak black horizontal"
          />
          <span className="sr-only">Acme Inc</span>
        </Link>

        <div className="flex justify-between w-full items-center">
          <nav className="ml-0 hidden lg:flex gap-6">
            <NavigationMenu>
              <NavigationMenuList>
                <NavigationMenuItem>
                  <NavigationMenuLink asChild>
                    <Link
                      href="/"
                      className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-gray-100/50 data-[state=open]:bg-gray-100/50 "
                    >
                      Home
                    </Link>
                  </NavigationMenuLink>
                </NavigationMenuItem>
                <NavigationMenuItem>
                  <NavigationMenuTrigger className="group bg-opacity-0 inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-gray-100/50 data-[state=open]:bg-gray-100/50 ">
                    About
                  </NavigationMenuTrigger>
                  <NavigationMenuContent className="p-10">
                    About content here
                  </NavigationMenuContent>
                </NavigationMenuItem>
                <NavigationMenuItem>
                  <NavigationMenuLink asChild>
                    <Link
                      href="/services"
                      className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-gray-100/50 data-[state=open]:bg-gray-100/50 "
                    >
                      Services
                    </Link>
                  </NavigationMenuLink>
                </NavigationMenuItem>
                <NavigationMenuItem>
                  <NavigationMenuLink asChild>
                    <Link
                      href="/contact"
                      className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-gray-100/50 data-[state=open]:bg-gray-100/50 "
                    >
                      Contact
                    </Link>
                  </NavigationMenuLink>
                </NavigationMenuItem>
              </NavigationMenuList>
            </NavigationMenu>
          </nav>
          <div className="hidden lg:flex text-sm ">
            <button className="p-2 rounded-lg mr-2 tracking-wider">PL</button>
            <button className="bg-orange-400 p-2 rounded-lg tracking-wider">
              ENG
            </button>
          </div>
        </div>
      </header>
    </div>
  );
}

function MenuIcon(props) {
  return (
    <svg
      {...props}
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <line x1="4" x2="20" y1="12" y2="12" />
      <line x1="4" x2="20" y1="6" y2="6" />
      <line x1="4" x2="20" y1="18" y2="18" />
    </svg>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:42:04