nino
  • ドキュメント
  • レジストリ
  • メンバーシップ

Command Palette

Search for a command to run...

スポンサー
メニュー

Breadcrumb(パンくず)

 

2分 4秒

  1. パンくずプロバイダー&定義用コンポーネントの作成
  2. パンくずコンポーネントを作成
  3. レイアウトにパンくずプロバイダーとパンくずコンポーネントを設置
  4. 各画面でパンくずを定義

パンくずプロバイダーと定義用コンポーネントの作成

Loading...

パンくずコンポーネントの作成

内部的に shadcn/ui の Breadcrumb を使用します。

Loading...

レイアウトにパンくずプロバイダーとパンくずコンポーネントを設置

Loading...

各画面でパンくずを定義

Loading...

このアプローチにより、宣言的にパンくずを定義でき、ページもサーバーコンポーネントのままキープできます。

動的ルートの場合

Loading...
Discord で質問する
何か気になったこと、分からないことがあれば気軽に質問してください!
DiscordDiscordで質問する
nino

Developer

XXGitHubGitHubYouTubeYouTubeZennZennDiscordDiscord

    リンク

  • ドキュメント
  • レジストリ
  • アーキテクチャ

    ツール

  • フィード
  • ステータス

    ポリシー

  • 利用規約
  • プライバシーポリシー
  • 特定商取引法に基づく表示
ドキュメント
はじめに
  • Changelog
ガイド
  • Webアプリの環境構築
  • ニュース収集&AI要約
  • Turso のテーブル移行
  • 日時の管理
  • 中規模のリストをブラウザにキャッシュし、クライアントでフィルタする
  • Search Params Dialog
  • コードの整理
  • AGENTS.md
  • Better Auth
  • プロダクト開発ポリシー
  • 推奨ツール
  • Proxy.ts
  • 多言語対応
  • SWR
  • Cache Component
  • Next.js の課題、不具合
  • アプリ開発フロー
  • プロンプトガイド
  • CSS Tips
  • Font Family
  • セルフブランディング
  • セルフオンボーディング
  • オフィスツール
  • Email
  • Breadcrumb(パンくず)
  • 並べ替え
"use client";

import { createContext, use, useEffect, useState } from "react";

type BreadCrumbItem = {
  label: string;
  href?: string;
};

const BreadcrumbContext = createContext<{
  breadcrumbs: BreadCrumbItem[];
  setBreadcrumbs: (breadcrumbs: BreadCrumbItem[]) => void;
}>({
  breadcrumbs: [],
  setBreadcrumbs: () => {},
});

export function BreadcrumbProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const [breadcrumbs, setBreadcrumbs] = useState<BreadCrumbItem[]>([]);
  return (
    <BreadcrumbContext value={{ breadcrumbs, setBreadcrumbs }}>
      {children}
    </BreadcrumbContext>
  );
}

export function BreadcrumbConfig({ items }: { items: BreadCrumbItem[] }) {
  const { setBreadcrumbs } = use(BreadcrumbContext);

  useEffect(() => {
    setBreadcrumbs(items);

    return () => {
      setBreadcrumbs([]);
    };
  }, []);

  return null;
}

export const useBreadcrumbs = () => {
  return use(BreadcrumbContext);
};
"use client";

import Link from "next/link";

import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@workspace/ui/components/breadcrumb";
import { Home } from "lucide-react";
import { Fragment } from "react/jsx-runtime";
import { useBreadcrumbs } from "./breadcrumb-provider";

export function MainBreadCrumb() {
  const { breadcrumbs } = useBreadcrumbs();

  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink asChild>
            <Link href="/admin">
              <Home className="size-5" />
            </Link>
          </BreadcrumbLink>
        </BreadcrumbItem>
        {breadcrumbs.map((breadcrumb) => (
          <Fragment key={breadcrumb.label}>
            <BreadcrumbSeparator />
            <BreadcrumbItem key={breadcrumb.label}>
              {breadcrumb.href ? (
                <BreadcrumbLink asChild>
                  <Link href={breadcrumb.href}>{breadcrumb.label}</Link>
                </BreadcrumbLink>
              ) : (
                <BreadcrumbPage>{breadcrumb.label}</BreadcrumbPage>
              )}
            </BreadcrumbItem>
          </Fragment>
        ))}
      </BreadcrumbList>
    </Breadcrumb>
  );
}
// ...
return (<>
  <BreadcrumbProvider>
    <BreadcrumbMain />
    {children}
  </BreadcrumbProvider>
</>)
import { BreadcrumbConfig } from "@/components/breadcrumb-provider";

export default function Page() {
  return (
    <div>
      <BreadcrumbConfig items={[{ label: "設定", href: "/settings" }]} />
      <h1>Page</h1>
    </div>
  )
}
import { BreadcrumbConfig } from "@/components/breadcrumb-provider";

export default async function Page({ params }: PageProps<"/posts/[id]">) {
  const id = (await params).id;
  const post = await getPost(id);

  return (
    <div>
      <BreadcrumbConfig items={[
        { label: "ホーム", href: "/" },
        { label: "ポスト", href: "/posts" },
        { label: post.title },
      ]} />
      <h1>{post.title}</h1>
    </div>
  );
}