๐Ÿก ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ: ์ฐœํ•˜๊ธฐ ๋ฐ ๋Œ“๊ธ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ (5)

ฮต( ฮต ห™ยณห™)ะท โ—‹ยบยท2025๋…„ 7์›” 31์ผ
0
post-thumbnail

๋ณธ ๊ธ€์€ ํŒจ์ŠคํŠธ์บ ํผ์Šค โ€“ Next.js ์‹ค๋ฌด ๊ฐ•์˜ ์ค‘ Part 8. Next.js 13์œผ๋กœ ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ ๋งŒ๋“ค๊ธฐ๋ฅผ ์ˆ˜๊ฐ•ํ•˜๋ฉฐ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ™๐Ÿป


๐Ÿฉท ์ˆ™์†Œ ์ƒ์„ธํŽ˜์ด์ง€์— ์ฐœํ•˜๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

โ–ช๏ธ ์ฐœํ•˜๊ธฐ(Like) ์Šคํ‚ค๋งˆ ๋ชจ๋ธ๋ง

์ฐœํ•˜๊ธฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž(User)์™€ ์ˆ™์†Œ(Room) ๊ฐ„์˜ N:M ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” Like ๋ชจ๋ธ์„ ์ถ”๊ฐ€์ ์œผ๋กœ ์„ค๊ณ„ํ–ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ™์†Œ์— ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์กฐํ•ฉ์˜ Like ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ์ข‹์•„์š”๋ฅผ ํ•ด์ œํ•˜๋ฉด ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๊ฐ€ ์‚ญ์ œ๋œ๋‹ค.

model Like {
  id        Int      @id @default(autoincrement())
  roomId    Int
  userId    Int
  createdAt DateTime @default(now())

  room Room @relation(fields: [roomId], references: [id], onDelete: Cascade)
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, roomId])
}
  • roomId, userId: ์–ด๋–ค ์ˆ™์†Œ๋ฅผ ์–ด๋–ค ์‚ฌ์šฉ์ž๊ฐ€ ์ฐœํ–ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ด€๊ณ„ ํ‚ค
  • createdAt: ์ฐœํ•œ ์‹œ์  ๊ธฐ๋ก
  • onDelete: Cascade: ์ˆ™์†Œ ๋˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ๊ด€๋ จ ์ฐœ ๋ฐ์ดํ„ฐ๋„ ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜๋„๋ก ์„ค์ •
  • @@index([userId, roomId]): ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ์ˆ™์†Œ๋ฅผ ์ค‘๋ณต์œผ๋กœ ์ฐœํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ฑฐ๋‚˜ userId + roomId ๊ธฐ๋ฐ˜์˜ ๋น ๋ฅธ ์กฐํšŒ๋ฅผ ์œ„ํ•œ ์ธ๋ฑ์Šค ์„ค์ •

๐Ÿ’ก

  • POST /api/likes: roomId์™€ userId ์กฐํ•ฉ์œผ๋กœ ์ฐœ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑ ๋˜๋Š” ์‚ญ์ œ
  • GET /api/rooms: ํ•ด๋‹น roomId์— ๋Œ€ํ•œ ์ฐœ ๋ชฉ๋ก ํ™•์ธ
  • ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” Like ๋ฐ์ดํ„ฐ์˜ ์œ ๋ฌด์— ๋”ฐ๋ผ UI ์ƒํƒœ๋ฅผ ์กฐ๊ฑด ๋ถ„๊ธฐํ•˜์—ฌ ํ‘œ์‹œ

โ–ช๏ธ LikeButton ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ์™€ ์„ค๊ณ„

  • roomId๋ฅผ props๋กœ ์ „๋‹ฌ๋ฐ›์•„ ํ˜„์žฌ ์ˆ™์†Œ ์ •๋ณด๋ฅผ ์กฐํšŒ
  • ์ฐœ ์—ฌ๋ถ€ ํ™•์ธ์„ ์œ„ํ•ด /api/rooms?id=${roomId}๋กœ GET ์š”์ฒญ
  • ์‘๋‹ต ๋ฐ์ดํ„ฐ์˜ isLiked ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ปดํฌ๋„ŒํŠธ์˜ UI ์ƒํƒœ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๋ Œ๋”๋ง
  • ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜ํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด toggleLike ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜์—ฌ /api/likes/route์— POST ์š”์ฒญ์„ ์ „์†ก

  const toggleLike = async () => {
    // ์ฐœํ•˜๊ธฐ / ์ฐœ ์ทจ์†Œํ•˜๊ธฐ ๋กœ์ง
    if (session?.user && room) {
      try {
        const like = await axios.post('/api/likes', {
          roomId: room.id,
        })

        if (like.status === 201) {
          toast.success('์ˆ™์†Œ๋ฅผ ์ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.')
        } else {
          toast.error('์ฐœ์„ ์ทจ์†Œํ–ˆ์Šต๋‹ˆ๋‹ค.')
        }

        refetch()
      } catch (e) {
        console.log(e)
        toast.error('์ฐœ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•˜๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.')
      }
    } else {
      toast.error('๋กœ๊ทธ์ธ ํ›„ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.')
    }
  }

โ–ช๏ธ Like API ์„ค๊ณ„ (Next.js Route Handler)

  • /api/likes/route ์ฐœ ํ† ๊ธ€ API
    ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ํ•˜๋‚˜์˜ ํ† ๊ธ€ ํ•จ์ˆ˜๋กœ ์ฐœ ์—ฌ๋ถ€๋ฅผ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก POST ์š”์ฒญ ๊ธฐ๋ฐ˜์˜ ๋‹จ์ผ API๋กœ ์„ค๊ณ„ํ–ˆ๋‹ค.
    ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜ํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ๊ธฐ์กด์— ์ฐœํ•œ ์ƒํƒœ์ธ์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋“ฑ๋ก ๋˜๋Š” ์ทจ์†Œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    ์ด ๋กœ์ง์€ Next.js์˜ app/api Route Handler๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์˜ ์—”๋“œํฌ์ธํŠธ์—์„œ ํ†ตํ•ฉ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
export async function POST(req: Request) {
  const { roomId } = await req.json();
  const session = await getServerSession(authOptions);

  if (!session?.user?.id) {
    return new NextResponse('Unauthorized', { status: 401 });
  }

  // ํ˜„์žฌ ์œ ์ €๊ฐ€ ์ด roomId์— ๋Œ€ํ•ด ์ด๋ฏธ ์ฐœํ–ˆ๋Š”์ง€ ํ™•์ธ
  const existingLike = await prisma.like.findFirst({
    where: {
      roomId,
      userId: session.user.id,
    },
  });

  if (existingLike) {
    // ์ด๋ฏธ ์ฐœํ•œ ์ƒํƒœ (์‚ญ์ œ ์ฒ˜๋ฆฌ)
    const like = await prisma.like.delete({
      where: { id: existingLike.id },
    });
    return NextResponse.json(like, { status: 200 });
  } else {
    // ์ฐœํ•œ ์  ์—†์Œ (์ƒˆ๋กœ ์ƒ์„ฑ)
    const like = await prisma.like.create({
      data: {
        roomId,
        userId: session.user.id,
      },
    });
    return NextResponse.json(like, { status: 201 });
  }
}
  • /api/likes๋Š” ๋‹จ์ผ API๋กœ ์ฐœ ๋“ฑ๋ก ๋ฐ ํ•ด์ œ๋ฅผ ๋ชจ๋‘ ์ฒ˜๋ฆฌ
  • ๋‚ด๋ถ€์—์„œ roomId + userId ์กฐํ•ฉ์œผ๋กœ ๊ธฐ์กด Like ๋ ˆ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
    (์กด์žฌํ•˜๋ฉด ์‚ญ์ œ, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ)
  • ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ณต์žกํ•œ ๋ถ„๊ธฐ ์—†์ด ํ•˜๋‚˜์˜ toggleLike() ํ•จ์ˆ˜๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • ์ฐœํ•˜๊ธฐ ๊ธฐ๋Šฅ์€ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— API ์š”์ฒญ ์‹œ next-auth์˜ getServerSession()์„ ํ†ตํ•ด ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์—์„œ ํ™•์ธํ•˜๊ณ  ์ธ์ฆ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค.
  • /api/rooms/route: ์ฐœ ์—ฌ๋ถ€ ํ™•์ธ API
    GET ์š”์ฒญ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ roomId์™€ userId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ ํŠน์ • ์ˆ™์†Œ๊ฐ€ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ฐœ ๋ชฉ๋ก์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€๋ฅผ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
if (id) {
  // ์ˆ™์†Œ ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ
  const room = await prisma.room.findUnique({
    where: { id: parseInt(id) },
    include: {
      likes: {
        where: session ? { userId: session?.user?.id } : {},
      },
    },
  });
}

include.likes๋ฅผ ํ†ตํ•ด Room ๋ชจ๋ธ๊ณผ Like ๋ชจ๋ธ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ™œ์šฉํ•ด ์ฐœ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•œ๋‹ค. ์ด๋•Œ ์กฐ๊ฑด์œผ๋กœ userId === ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ID๋ฅผ ์ ์šฉํ•˜์—ฌ ํ•ด๋‹น ์ˆ™์†Œ๋ฅผ ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ฐœํ•œ ๊ฒฝ์šฐ์—๋งŒ likes ๋ฐฐ์—ด์— ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋œ๋‹ค. ๋”ฐ๋ผ์„œ room.likes.length > 0์ด๋ฉด ์ฐœํ•œ ์ƒํƒœ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ฐœํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ’ฌ ์ˆ™์†Œ ์ƒ์„ธํŽ˜์ด์ง€์— ๋Œ“๊ธ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

โ–ช๏ธ ๋Œ“๊ธ€(Comment) ์Šคํ‚ค๋งˆ ๋ชจ๋ธ๋ง

๋Œ“๊ธ€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž(User)์™€ ์ˆ™์†Œ(Room) ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” Comment ๋ชจ๋ธ์„ ์„ค๊ณ„ํ–ˆ๋‹ค. Like ๋ชจ๋ธ๊ณผ ๊ฑฐ์˜ ๋น„์Šทํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•˜๋ฉด ํ•ด๋‹น ์ˆ™์†Œ์™€ ์œ ์ €์— ์—ฐ๊ฒฐ๋œ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ ๋ณธ๋ฌธ ๋‚ด์šฉ์€ body ํ•„๋“œ์— ์ €์žฅ๋œ๋‹ค.

model Comment {
  id         Int      @id @default(autoincrement())
  createdAt  DateTime @default(now())
  roomId     Int
  userId     String
  body       String

  room Room  @relation(fields: [roomId], references: [id], onDelete: Cascade)
  user User  @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, roomId])
}
  • roomId, userId: ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•œ ์ˆ™์†Œ์™€ ์‚ฌ์šฉ์ž ๊ฐ„์˜ ๊ด€๊ณ„ ํ‚ค
  • body: ๋Œ“๊ธ€ ๋ณธ๋ฌธ ๋‚ด์šฉ
  • createdAt: ๋Œ“๊ธ€ ์ž‘์„ฑ ์‹œ๊ฐ (์ž๋™ ๊ธฐ๋ก)
  • onDelete: Cascade: ์‚ฌ์šฉ์ž ๋˜๋Š” ์ˆ™์†Œ๊ฐ€ ์‚ญ์ œ๋  ๊ฒฝ์šฐ ๊ด€๋ จ ๋Œ“๊ธ€๋„ ํ•จ๊ป˜ ์‚ญ์ œ
  • @@index([userId, roomId]): ์œ ์ €/์ˆ™์†Œ ๊ธฐ์ค€์œผ๋กœ ๋น ๋ฅธ ์กฐํšŒ๋ฅผ ์œ„ํ•œ ์ธ๋ฑ์Šค ์„ค์ •


โ–ช๏ธ Comment ๋Œ“๊ธ€ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ

๋Œ“๊ธ€ ๊ธฐ๋Šฅ์€ ์ž…๋ ฅ๊ณผ ์กฐํšŒ, ์ „์ฒด ๋ณด๊ธฐ๋กœ ๋‚˜๋‰˜๋ฉฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ธ ๊ฐ€์ง€ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ์ž…๋ ฅ ์˜์—ญ๊ณผ ์กฐํšŒ ์˜์—ญ์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

  • CommentForm: ๋Œ“๊ธ€์„ ์ž…๋ ฅํ•˜๋Š” ์˜์—ญ
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜๋ฉด onChange ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ†ตํ•ด ์ƒํƒœ(state)์— ๊ฐ’์ด ์ €์žฅ
  • ์ž…๋ ฅ ํ›„ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด /api/comments์— POST ์š”์ฒญ์„ ๋ณด๋‚ด ๋Œ“๊ธ€์„ ์ƒ์„ฑ

  • CommentList: ์ตœ์‹  ๋Œ“๊ธ€ ๋ชฉ๋ก(์ตœ๋Œ€ 6๊ฐœ)์„ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ
  • ์ƒ์„ธ ํŽ˜์ด์ง€ ๋‚ด์—์„œ ๊ฐ„๋‹จํžˆ ํ™•์ธ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์ŠคํŠธ UI
  • โ€˜ํ›„๊ธฐ ๋ชจ๋‘ ๋ณด๊ธฐโ€™ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ CommentListModal์„ ์—ด์–ด ์ „์ฒด ๋Œ“๊ธ€ ํ™•์ธ ๊ฐ€๋Šฅ

  • CommentListModal: ๋ชจ๋“  ๋Œ“๊ธ€์„ ๋ชจ๋‹ฌ ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ
  • /api/comments์— GET ์š”์ฒญ์„ ๋ณด๋‚ด ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  • IntersectionObserver์™€ useInfiniteQuery๋ฅผ ํ™œ์šฉํ•ด ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„


โ–ช๏ธ ๋Œ“๊ธ€ ๊ธฐ๋Šฅ ์„ค๊ณ„: Comment API ๊ตฌ์กฐ

๋Œ“๊ธ€ ๊ธฐ๋Šฅ์€ /api/comments/route์—์„œ ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.

  • POST /api/comments: ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์ธ์ฆ
    ๋Œ“๊ธ€ ์ž‘์„ฑ ์‹œ ํด๋ผ์ด์–ธํŠธ์—์„œ roomId์™€ body(๋Œ“๊ธ€ ๋‚ด์šฉ)๋ฅผ ๋ณด๋‚ด๋ฉด ์„œ๋ฒ„์—์„œ๋Š” getServerSession์œผ๋กœ ์ธ์ฆ๋œ ์œ ์ € ์ •๋ณด๋ฅผ ํ™•์ธํ•œ ํ›„, ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ๋Œ“๊ธ€์„ ์ƒ์„ฑํ•œ๋‹ค.
export async function POST(req: Request) {
  const session = await getServerSession(authOptions);
  const formData = await req.json();
  const { roomId, body }: { roomId: number; body: string } = formData;

  const comment = await prisma.comment.create({
    data: {
      roomId,
      body,
      userId: session?.user.id,
    },
  });

  return NextResponse.json(comment, { status: 200 });
}
  • getServerSession(authOptions)๋กœ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์—ฌ๋ถ€ ํ™•์ธ
  • ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด 401 Unauthorized ๋ฐ˜ํ™˜
  • ์ธ์ฆ๋œ ์œ ์ €๋ผ๋ฉด roomId, body, userId๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋Œ“๊ธ€ ์ƒ์„ฑ
  • GET /api/comments?roomId=1&limit=6: ํŠน์ • ์ˆ™์†Œ์˜ ๋Œ“๊ธ€์„ ์กฐํšŒ
    GET ์š”์ฒญ์—์„œ๋Š” searchParams๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ถ„๊ธฐํ•˜์—ฌ ๋‘ ๊ฐ€์ง€ ์กฐํšŒ ๋ฐฉ์‹์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  1. page ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ (๋ฌดํ•œ ์Šคํฌ๋กค)
if (page) {
  const count = await prisma.comment.count({ where: { roomId } });
  const comments = await prisma.comment.findMany({
    where: { roomId },
    orderBy: { createdAt: 'desc' },
    take: limit,
    skip: (page - 1) * limit,
    include: { user: true },
  });

  return {
    data: comments,
    totalCount: count,
    totalPage: Math.ceil(count / limit),
    page,
  };
}
  • skip, take๋ฅผ ํ™œ์šฉํ•œ offset ๊ธฐ๋ฐ˜ pagination
  • ์ด ๊ฐœ์ˆ˜ count์™€ ํ•จ๊ป˜ totalPage๋„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—์„œ ํŽ˜์ด์ง€ ์ข…๋ฃŒ ์กฐ๊ฑด ํŒ๋‹จ ๊ฐ€๋Šฅ
  • include: { user: true }๋กœ ์‚ฌ์šฉ์ž ์ •๋ณด๋„ ํ•จ๊ป˜ ํฌํ•จ
  1. page ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๊ณ  limit๋งŒ ์กด์žฌํ•  ๊ฒฝ์šฐ (์ตœ์‹  ๋Œ“๊ธ€ 6๊ฐœ)
const comments = await prisma.comment.findMany({
  where: { roomId },
  orderBy: { createdAt: 'desc' },
  take: limit,
  include: { user: true },
});
  • ํŽ˜์ด์ง€ ์—†์ด ์ตœ์‹ ์ˆœ์œผ๋กœ N๊ฐœ๋งŒ ์กฐํšŒ (6๊ฐœ)
  • ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ํ•„์š” ์—†๋Š” CommentList์— ์ ํ•ฉ

๐Ÿ™‹๐Ÿปโ€โ™€๏ธ ๋งˆ์ดํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„: ๋‚ด๊ฐ€ ์“ด ๋Œ“๊ธ€ & ์ฐœํ•œ ์ˆ™์†Œ ๋ฆฌ์ŠคํŠธ

๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ ํ™œ๋™ ๋‚ด์—ญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก, ๋งˆ์ดํŽ˜์ด์ง€์—๋Š” โ€˜๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๋Œ“๊ธ€โ€™๊ณผ โ€˜์ฐœํ•œ ์ˆ™์†Œ ๋ฆฌ์ŠคํŠธโ€™ ํŽ˜์ด์ง€๋ฅผ ๊ฐ๊ฐ ๊ตฌํ˜„ํ–ˆ๋‹ค.

  • ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๋Œ“๊ธ€ ๋ชจ์•„๋ณด๊ธฐ
  • app/(home)/users/comments/page.tsx
  • app/api/comments/route.ts
  • ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๋Œ“๊ธ€ ๋ชฉ๋ก์„ ์กฐํšŒํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ๋กœ ์ถœ๋ ฅ
  • API: GET /api/comments (userId๋ฅผ ์กฐ๊ฑด์œผ๋กœ ํ•„ํ„ฐ๋ง๋œ ๋Œ“๊ธ€๋งŒ ์กฐํšŒ)

  • ๋‚ด๊ฐ€ ์ฐœํ•œ ์ˆ™์†Œ ๋ฆฌ์ŠคํŠธ
  • app/(home)/users/likes/page.tsx
  • app/api/likes/route.ts
  • ์‚ฌ์šฉ์ž๊ฐ€ ์ฐœํ•œ ์ˆ™์†Œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ๋กœ ์ถœ๋ ฅ
  • API: GET /api/likes (userId ๊ธฐ์ค€์œผ๋กœ Like ๋ชฉ๋ก ์กฐํšŒ ๋ฐ ์ˆ™์†Œ ์ •๋ณด ํฌํ•จ)

profile
์ฐจ๊ณก์ฐจ๊ณก ์Œ“์•„๋‘๊ธฐ ๐Ÿ’ญ

0๊ฐœ์˜ ๋Œ“๊ธ€