Menu

useSelectedLayoutSegment

useSelectedLayoutSegment 是一个 客户端组件 hook,允许你读取从调用它的布局 下一级 的活跃路由段。

它对于导航界面非常有用,例如父布局内的标签页,根据活跃的子段改变样式。

app/example-client-component.tsx
"use client";
 
import { useSelectedLayoutSegment } from "next/navigation";
 
export default function ExampleClientComponent() {
  const segment = useSelectedLayoutSegment();
 
  return <p>活跃段: {segment}</p>;
}
app/example-client-component.js
"use client";
 
import { useSelectedLayoutSegment } from "next/navigation";
 
export default function ExampleClientComponent() {
  const segment = useSelectedLayoutSegment();
 
  return <p>活跃段: {segment}</p>;
}

值得注意的是:

  • 由于 useSelectedLayoutSegment 是一个 客户端组件 hook,而布局默认是 服务端组件useSelectedLayoutSegment 通常通过导入到布局中的客户端组件调用。
  • useSelectedLayoutSegment 仅返回下一级的段。要返回所有活跃段,请参阅 useSelectedLayoutSegments

参数

const segment = useSelectedLayoutSegment(parallelRoutesKey?: string)

useSelectedLayoutSegment 可选地接受一个 parallelRoutesKey,允许你读取该槽位内的活跃路由段。

返回值

useSelectedLayoutSegment 返回一个字符串形式的活跃段,如果不存在则返回 null

例如,给定以下布局和 URL,返回的段将是:

布局访问的 URL返回的段
app/layout.js/null
app/layout.js/dashboard'dashboard'
app/dashboard/layout.js/dashboardnull
app/dashboard/layout.js/dashboard/settings'settings'
app/dashboard/layout.js/dashboard/analytics'analytics'
app/dashboard/layout.js/dashboard/analytics/monthly'analytics'

示例

创建一个活跃链接组件

你可以使用 useSelectedLayoutSegment 创建一个根据活跃段改变样式的活跃链接组件。例如,博客侧边栏中的精选文章列表:

app/blog/blog-nav-link.tsx
"use client";
 
import Link from "next/link";
import { useSelectedLayoutSegment } from "next/navigation";
 
// 这个 *客户端* 组件将被导入到一个博客布局中
export default function BlogNavLink({
  slug,
  children,
}: {
  slug: string;
  children: React.ReactNode;
}) {
  // 导航到 `/blog/hello-world` 将返回 'hello-world' 作为选中的布局段
  const segment = useSelectedLayoutSegment();
  const isActive = slug === segment;
 
  return (
    <Link
      href={`/blog/${slug}`}
      // 根据链接是否活跃改变样式
      style={{ fontWeight: isActive ? "bold" : "normal" }}
    >
      {children}
    </Link>
  );
}
app/blog/blog-nav-link.js
"use client";
 
import Link from "next/link";
import { useSelectedLayoutSegment } from "next/navigation";
 
// 这个 *客户端* 组件将被导入到一个博客布局中
export default function BlogNavLink({ slug, children }) {
  // 导航到 `/blog/hello-world` 将返回 'hello-world' 作为选中的布局段
  const segment = useSelectedLayoutSegment();
  const isActive = slug === segment;
 
  return (
    <Link
      href={`/blog/${slug}`}
      // 根据链接是否活跃改变样式
      style={{ fontWeight: isActive ? "bold" : "normal" }}
    >
      {children}
    </Link>
  );
}
app/blog/layout.tsx
// 将客户端组件导入到父布局(服务端组件)中
import { BlogNavLink } from "./blog-nav-link";
import getFeaturedPosts from "./get-featured-posts";
 
export default async function Layout({
  children,
}: {
  children: React.ReactNode;
}) {
  const featuredPosts = await getFeaturedPosts();
  return (
    <div>
      {featuredPosts.map((post) => (
        <div key={post.id}>
          <BlogNavLink slug={post.slug}>{post.title}</BlogNavLink>
        </div>
      ))}
      <div>{children}</div>
    </div>
  );
}
app/blog/layout.js
// 将客户端组件导入到父布局(服务端组件)中
import { BlogNavLink } from "./blog-nav-link";
import getFeaturedPosts from "./get-featured-posts";
 
export default async function Layout({ children }) {
  const featuredPosts = await getFeaturedPosts();
  return (
    <div>
      {featuredPosts.map((post) => (
        <div key={post.id}>
          <BlogNavLink slug={post.slug}>{post.title}</BlogNavLink>
        </div>
      ))}
      <div>{children}</div>
    </div>
  );
}

版本历史

版本变更
v13.0.0引入 useSelectedLayoutSegment