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

Next.js 13+:SSR与客户端组件中实现导航激活链接的方法

Next.js 13+ 兼容SSR的导航激活链接实现方案

问题根源

之前的方案中,将全局RootLayout设为客户端组件并通过window.location.pathname传递路径,存在两个核心问题:

  • 客户端路由跳转(通过<Link>)时,window.location不会触发组件重渲染,导致激活状态无法实时更新,仅页面刷新后生效
  • 全局布局转为客户端组件会失去部分SSR优势,没必要将整个布局客户端化

最优解决方案:客户端组件+usePathname钩子

将Header组件单独设为客户端组件,使用Next.js 13+官方提供的usePathname钩子获取当前路径,既保留RootLayout的SSR能力,又能实时响应客户端路由变化。

1. 修改Header组件为客户端组件

'use client';

import { usePathname } from 'next/navigation';
import Link from 'next/link';
import styles from './Header.module.css';

// 自定义路由配置,根据实际项目调整
const URL = [
  { path: '/', name: '首页' },
  { path: '/about', name: '关于我们' },
  { path: '/products', name: '产品列表' },
];

export default function Header() {
  const pathname = usePathname();

  return (
    <nav className={styles.navigation}>
      <ul>
        {URL.map(route => (
          <li key={route.path}>
            <Link
              className={route.path === pathname ? styles.highlighted : ''}
              href={route.path}
            >
              {route.name}
            </Link>
          </li>
        ))}
      </ul>
    </nav>
  );
}

2. 恢复RootLayout为服务器组件

移除RootLayout中的'use client'指令,保持其SSR特性,直接引入Header组件即可:

import * as React from 'react';
import { Footer, Header, Sidebar } from '../components';
import '../styles/globals.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <div className='wrapper'>
          <Header /> {/* 无需传递pathname,Header内部自动获取 */}
          <Sidebar />
          {children}
          <Footer />
        </div>
      </body>
    </html>
  );
}

方案说明

  • usePathname是Next.js专为app router设计的客户端钩子,会自动监听客户端路由变化,实时更新当前路径,确保激活状态同步
  • RootLayout保持服务器组件,保证页面初始渲染的SSR性能和SEO友好性
  • 仅将需要交互的Header转为客户端组件,遵循Next.js的"渐进式客户端组件"最佳实践

备选方案:服务器组件中获取路径(静态场景)

如果你的页面都是静态渲染,无需动态客户端导航,可以在服务器组件中通过headers()获取初始路径,但注意该路径仅在服务器渲染时生效,客户端导航时不会更新:

import { headers } from 'next/headers';

export default function StaticHeader() {
  const headersList = headers();
  const pathname = headersList.get('x-nextjs-pathname') || '/';

  return (
    <nav className={styles.navigation}>
      <ul>
        {URL.map(route => (
          <li key={route.path}>
            <Link
              className={route.path === pathname ? styles.highlighted : ''}
              href={route.path}
            >
              {route.name}
            </Link>
          </li>
        ))}
      </ul>
    </nav>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:21:11