🐱
【Newt / Next.js】カテゴリに属するタグ一覧を取得する方法
やりたいこと
ページのサイドバーに「カテゴリ」>「タグ」のアコーディオンメニューを作りたい。
前提
基本設定
基本はチュートリアル通りにセットアップ済み
カテゴリのフィールド
UID: category
フィールド名 | フィールド ID |
---|---|
名前 | name |
スラッグ | catSlug |
types/category.ts
import type { Content } from 'newt-client-js'
export interface Category extends Content {
name: string
catSlug: string
}
タグのフィールド
UID: tag
フィールド名 | フィールド ID |
---|---|
名前 | name |
スラッグ | tagSlug |
カテゴリー | category |
types/tag.ts
import type { Content } from 'newt-client-js'
import type { Category } from '@/types/category'
export interface Tag extends Content {
name: string
tagSlug: string
category: Category
}
アコーディオンメニューの UI
shadcn/uiで作成
実装方法
1. カテゴリ・タグ一覧の取得メソッドを作成する
- カテゴリ一覧の取得メソッド
lib/newt.ts
export const getCategories = cache(async (): Promise<Category[]> => {
const { items: categories } = await client.getContents<Category>({
appUid: process.env.NEWT_APP_UID,
modelUid: 'category',
query: {
order: ['_sys.customOrder'],
},
})
return categories
})
- タグ一覧の取得メソッド
lib/newt.ts
export const getTags = async (query?: GetContentsQuery,): Promise<Tag[]> => {
const { items: tags } = await client.getContents<Tag>({
appUid: process.env.NEWT_APP_UID,
modelUid: 'tag',
query: {
order: ['_sys.customOrder'],
...query,
},
})
return tags
}
getTags
のclient.getContents
にquery
の引数を渡すことで、任意の条件でタグ一覧を取得できます。
2. カテゴリ一覧を表示する
components/Sidebar.tsx
import { getCategories } from '@/lib/newt'
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
export default async function Sidebar() {
// タグ一覧の情報を取得
const categories = await getCategories()
return (
<Accordion type="multiple" className="mat-2">
{
// タグ一覧を表示
categories.map((category) => {
return (
<AccordionItem key={category._id} value={category._id}>
<AccordionTrigger>
<Link href={`/${category.catSlug}`}>{category.name}</Link>
</AccordionTrigger>
<AccordionContent>
~~ タグ一覧を表示する ~~
</AccordionContent>
</AccordionItem>
)
})
}
</Accordion>
)
}
3. タグ一覧を表示する
components/Sidebar.tsx
import { getCategories } from '@/lib/newt'
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
export default async function Sidebar() {
const categories = await getCategories()
const categoriesWithTags = await Promise.all(categories.map(async (category) => {
const tags = await getTags({ category: category._id })
return { ...category, tags }
}))
return (
<Accordion type="multiple" className="mat-2">
{
categoriesWithTags.map((category) => {
const tags = category.tags;
return (
<AccordionItem key={category._id} value={category._id}>
<AccordionTrigger>
<Link href={`/${category.catSlug}`}>{category.name}</Link>
</AccordionTrigger>
<AccordionContent>
<ul className="flex flex-col items-start">
{
tags.map((tag) => {
return (
<Button key={tag._id} asChild variant="ghost" className="text-left w-full flex items-start justify-start">
<Link href={`/${category.catSlug}/${tag.tagSlug}`}>{tag.name}</Link>
</Button>
)
})
}
</ul>
</AccordionContent>
</AccordionItem>
)
})
}
</Accordion>
)
}
Discussion