ブログ詳細ページでコメント情報を取得するようにします。

型定義

コメントといいねのデータベースを追加したので、型定義を修正します。

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 は直接プロフィールテーブルに紐づいていないので、効率がよくないです。

プロフィールテーブルを参照して紐づけておくと、効率よく情報を取得することができます。

ぜひ試してみてください。

確認

ここまででエラーがないか確認しておきます。