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

Next.js 14根布局中Navbar路由选中状态管理问题

解决方案

要在保持Navbar为服务器组件的前提下解决导航选中状态不更新的问题,同时支持路由条件显示,可以通过拆分组件的方式实现:将Navbar主体保留为服务器组件,仅把需要动态响应路由变化的导航项部分做成客户端组件。

步骤1:修改Navbar服务器组件

更新Navbar组件,使用Next.js提供的x-nextjs-pathname头(而非referer)获取服务器端渲染时的当前路径,同时保留异步翻译逻辑和全局布局结构:

import { headers } from "next/headers";
import { useTranslation } from "../i18n";
import Link from "next/link";
import NavbarItem from "./NavbarItem"; // 后续创建的客户端组件

interface Props {
  children: React.ReactNode;
}

export default async function Navbar({ children }: Props) {
  // 服务器端可靠获取当前路径
  const pathname = headers().get('x-nextjs-pathname') || '/';
  const { t } = await useTranslation("it", "common");

  return (
    <>
      <nav className="px-4 py-4 text-gray-400 dark:text-gray-200 absolute h-24 w-full z-50 align-middle justify-center">
        <div className="h-full flex">
          <div className="flex w-full justify-between lg:justify-center my-auto">
            <NavbarItem
              name={t("NAVBAR.HOME")}
              to="/"
              initialPathname={pathname}
            />
            <NavbarItem
              name={t("NAVBAR.PROJECTS")}
              to="/projects"
              initialPathname={pathname}
            />
            <NavbarItem
              name={t("NAVBAR.INFOS")}
              to="/about-me"
              initialPathname={pathname}
            />
            {/* 服务器端路由条件显示示例:非/admin页面显示Contact项 */}
            {pathname !== '/admin' && (
              <NavbarItem
                name={t("NAVBAR.CONTACT")}
                to="/contact"
                initialPathname={pathname}
              />
            )}
          </div>
        </div>
      </nav>
      {children}
    </>
  );
}

步骤2:创建客户端组件NavbarItem

新建NavbarItem.tsx作为客户端组件,使用usePathname监听客户端路由变化,动态更新选中状态,同时支持客户端侧的路由条件显示:

'use client';

import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";

interface NavbarItemProps {
  name: string;
  to: string;
  initialPathname: string;
}

export default function NavbarItem({ name, to, initialPathname }: NavbarItemProps) {
  // 初始化选中状态(来自服务器端的初始路径)
  const [isSelected, setIsSelected] = useState(initialPathname === to);
  const pathname = usePathname();

  // 监听路由变化,更新选中状态
  useEffect(() => {
    setIsSelected(pathname === to);
  }, [pathname, to]);

  // 客户端路由条件显示示例:非/secret页面显示当前项
  const shouldShow = pathname !== '/secret';
  if (!shouldShow) return null;

  return (
    <Link locale="en" href={to}>
      <h1
        className={`lg:text-xl text-lg px-2 lg:px-2 lg:mx-14 py-2 cursor-pointer hover:underline select-none w-24 lg:w-44 flex justify-center ${
          isSelected
            ? "bg-gray-300/25 rounded-xl text-gray-400 dark:text-gray-100 font-bold"
            : ""
        }`}
      >{name}</h1>
    </Link>
  );
}

核心优势

  1. Navbar仍为服务器组件:保留异步翻译、服务器端数据获取等能力,无需在每个页面重复导入,全局生效。
  2. 精准获取路径:使用x-nextjs-pathname头替代referer,避免上一页URL干扰,服务器端路径获取更可靠。
  3. 动态响应客户端导航:仅将导航项部分设为客户端组件,通过usePathname监听路由变化,实时更新选中状态。
  4. 双向路由控制:服务器端可通过初始pathname判断导航项显示,客户端可通过实时pathname做动态控制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:41:26