Tailwind Logo

パンくずリストのコンポーネントを作成する

XM CloudHeadless SXA

公開日: 2024-03-06

前回の LinkList の動作を応用して、今回はパンくずリストのコンポーネントを作ってみたいと思います。

空のコンポーネントを作成する

まずは空っぽのコンポーネントを作成したいと思います。ウィザードを利用すると簡単に初期設定を作成することができます。

上記のページと異なる手順として、

  • コンポーネント名を Breadcrumb
  • コンポーネントのファイルは src\components\Navigation\Breadcrumb.tsx
  • Other properties は設定しない
  • Open Properties after Add の項目は No
  • Datasource Template は削除する(テンプレートのアイテムも不要です)

これで準備は出来ました。

GraphQL を準備する

前回はアイテムの1つ下にあるリンクリスト一覧を取得する形でしたが、今回は該当するアイテムから遡ってナビゲーションタイトルを取得したいと思います。実際のクエリは以下の通りです。

GraphQL
fragment breadcrumbFields on Item {
    field(name: "NavigationTitle") {
      ... on TextField {
        value
      }
    }
  url {
    path
  }
}
query BreadcrumbQuery($contextItem: String!, $language: String!)  {
  # Assume the item id is available on the page
  item(path: $contextItem, language: $language) {
    ancestors(
      hasLayout: true
      includeTemplateIDs: "B4283FEF-AE4E-4992-82E7-33B170C7A7DE"
    ) {
      ...breadcrumbFields
    }
  }
}

includeTemplateIDs の GUID は、Page テンプレートのアイテム ID を指定しています。

breadcrumb06.png

これに対して、以下の Query Variables を指定します。

JSON
{
  "contextItem": "74010881-DF60-4FB0-973A-C109959E2E9B",
  "language": "en"
}

この contextItem の項目は、そのアイテムの ID を指定するようにします。結果として、以下の Json データを取得することができます。

JSON
{
  "data": {
    "item": {
      "ancestors": [
        {
          "field": {
            "value": "Resource"
          },
          "url": {
            "path": "/resource"
          }
        },
        {
          "field": {
            "value": "Home"
          },
          "url": {
            "path": "/"
          }
        }
      ]
    }
  }
}

該当するアイテムから Home までのアイテムの Navigation Title と Path を取得することができました。このクエリを GraphQL にコピーします。

breadcrumb01.png

コンポーネントのコードを変更する

今回はパンくずリストとして動作するかどうか、コードを入れて確認をしていきたいと思います。まず、返ってくる Json のデータを扱うことができるように Interface を定義してしまいます。

TypeScript
interface Ancestor {
  field: {
    value: string;
  };
  url: {
    path: string;
  };
}

interface Fields {
  data: {
    item: {
      ancestors: Ancestor[];
    };
  };
}

続いて関数の呼び出し部分を書き換えます。

TypeScript
type BreadcrumbProps = {
  params: { [key: string]: string };
  fields: Fields;
};

export const Default = (props: BreadcrumbProps): JSX.Element => {

これで Json Rendering のアイテムに定義した GraphQL のデータに合わせて動くようになりました。また、コンポーネントが正しく動いているかを確認するために、以下のコードを追加します。

TypeScript
import { useSitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs';

最後に、上記ですでに BreadcrumbProps を利用して呼び出す Default の中身の動作を以下のように書き換えます。

TypeScript
export const Default = (props: BreadcrumbProps): JSX.Element => {
  const data = props.fields?.data;
  const { sitecoreContext } = useSitecoreContext();

  if (data.item.ancestors.length > 0) {
    return (
      <div className="component-content">
        <div>Item OK </div>
        <div>id: {sitecoreContext.itemId}</div>
      </div>
    );
  }

  return (
    <div className="component-content">
      <div>No Item </div>
      <div>id: {sitecoreContext.itemId}</div>
    </div>
  );
};

これで準備が整いました。データを取得していれば Item OK の文字と、そのページの Sitecore のアイテムのアイテム ID が表示されるはずです。

breadcrumb02.png

アイテム ID を参照すると、正しく値を取得していることがわかります。

breadcrumb03.png

データの取得ができていることを確認できました。取得できているデータを一覧として表示するための関数を準備します。

TypeScript
function generateBreadcrumbList(ancestors: Ancestor[]): JSX.Element {
  // Iterate through ancestors and generate li elementss
  const ancestorListItems = ancestors.map((ancestor: Ancestor, index: number) => {
    return (
      <li key={index}>
        <a href={ancestor.url.path}>{ancestor.field.value}</a>
      </li>
    );
  });

  // Wrap the list items with ul tags and return the JSX element
  return <ul>{ancestorListItems}</ul>;
}

これを呼び出すように書き換えます。

TypeScript
  if (data) {
    return <div className="component-content">{generateBreadcrumbList(data.item.ancestors)}</div>;
  }

以下のように作成することができました。

breadcrumb04.png

パンくずリストとしては、順番が逆の方が良いので、以下のように関数を書き換えます。

TypeScript
function generateBreadcrumbList(ancestors: Ancestor[]): JSX.Element {
  const reversedAncestors = ancestors.reverse();

  const ancestorListItems = reversedAncestors.map((ancestor: Ancestor, index: number) => {

結果、以下のように表示されました。

breadcrumb05.png

スタイルを適用できるようにする

出来上がったコンポーネントに対して Style の設定ができるように、以下のようにコードを追加します。

TypeScript
export const Default = (props: BreadcrumbProps): JSX.Element => {
  const data = props.fields?.data;
  const styles = `component breadcrumb ${props.params.styles}`.trimEnd();
  const id = props.params.RenderingIdentifier;

  const { sitecoreContext } = useSitecoreContext();

  if (data) {
    return <div className="component-content">{generateBreadcrumbList(data.item.ancestors)}</div>;
  }

  return (
    <div className={styles} id={id ? id : undefined}>
      <div className="component-content">
        <div>No Item </div>
        <div>id: {sitecoreContext.itemId}</div>
      </div>
    </div>
  );
};

これで、パンくずリストを処理したい時には、breadcrumb を指定することで、スタイルシートの処理を追加できるようになりました。また、styles で CMS 側で持っているスタイルのデータを取得することもできました。

まとめ

今回は長くなりましたが、Next.js で作成するパンくずリストのサンプルを作成してみました。実際には GraphQL で対象となるデータを取得、それをコンポーネント側に渡して、取得して処理をする、という形になります。

参考ページ

関連タグ