このチャプターの目次
ブログ詳細ページでコメント情報を取得するようにします。
型定義
コメントといいねのデータベースを追加したので、型定義を修正します。
BlogListType
にコメントの型を追加します。
utils/blog.types.ts
export interface BlogListType {
id: string
created_at: string
title: string
content: string
user_id: string
image_url: string
name: string | null
avatar_url: string | null
comments: CommentType[]
}
export interface LikeType {
user_id: string
}
export interface ProfileType {
avatar_url: string | null
name: string | null
}
export interface CommentType {
id: string
content: string
created_at: string
profiles: ProfileType
likes: LikeType[]
}
コメント情報取得
ブログ詳細画面のサーバーコンポーネントでコメント情報を取得します。
app/blog/[blogid]/page.tsx
import { notFound } from 'next/navigation'
import { createClient } from '../../../utils/supabase-server'
import type { BlogListType } from '../../../utils/blog.types'
import BlogDetail from '../../components/blog/blog-detail'
type PageProps = {
params: {
blogId: string
}
}
// ブログ詳細
const BlogDetailPage = async ({ params }: PageProps) => {
const supabase = createClient()
// ブログ詳細取得
const { data: blogData } = await supabase
.from('blogs')
.select('*, comments(id, content, created_at, profiles(name, avatar_url), likes(user_id))') // コメント取得
.eq('id', params.blogId)
.returns<BlogListType>() // 型を指定
.single()
// ブログが存在しない場合
if (!blogData) return notFound()
// 【Tips】
// blogsテーブルのuser_idをprofile_idに変更することで、ブログと同時にプロフィールも取得できるようになります。
// supabase.from('blogs').select(`id, created_at, title, content, image_url, profiles(name, avatar_url), comments(id, content, created_at, profiles(name, avatar_url), likes(user_id))`).eq('id', params.blogId).returns<BlogListType>().single()
// こうすることで、別にプロフィールを取得する必要がなくなります。
// 試してみてください。
// プロフィール取得
const { data: profileData } = await supabase
.from('profiles')
.select()
.eq('id', blogData.user_id)
.single()
// 表示ブログ詳細作成
const blog: BlogListType = {
id: blogData.id,
created_at: blogData.created_at,
title: blogData.title,
content: blogData.content,
image_url: blogData.image_url,
user_id: blogData.user_id,
name: profileData!.name,
avatar_url: profileData!.avatar_url,
comments: blogData.comments,
}
return <BlogDetail blog={blog} />
}
export default BlogDetailPage
ブログ詳細とコメントを同時取得
select を工夫することで、ブログ詳細とコメントを同時に取得することができます。
const { data: blogData } = await supabase
.from('blogs')
.select('*, comments(id, content, created_at, profiles(name, avatar_url), likes(user_id))') // コメント取得
.eq('id', params.blogId)
.returns<BlogListType>() // 型を指定
.single()
.returns<BlogListType>()
で型を指定しておきます。
Tips
今のコードはプロフィール情報を別で取得していますが、blogs テーブルの user_id を profile_id に変更することで、ブログと同時にプロフィールも取得できるようになります。
supabase
.from('blogs')
.select(
`id, created_at, title, content, image_url, profiles(name, avatar_url), comments(id, content, created_at, profiles(name, avatar_url), likes(user_id))`
)
.eq('id', params.blogId)
.returns<BlogListType>()
.single()
user_id は直接プロフィールテーブルに紐づいていないので、効率がよくないです。
プロフィールテーブルを参照して紐づけておくと、効率よく情報を取得することができます。
ぜひ試してみてください。
確認
ここまででエラーがないか確認しておきます。