Develop/NEXT

[Next.js] 게시판 만들기(7) 댓글 기능 구현하기 feat.mongoDB

임성장 2023. 8. 15. 10:52
728x90
해당 내용은 코딩애플의 Next.js 강의 내용을 기반으로 하고 있다는 것을 알려드립니다.

핵심 로직

  1. 댓글 기능 UI 만들기
  2. 전송 버튼 누르면 댓글 데이터 서버에 전송하기
  3. 받은 데이터 서버에서 확인하고 DB에 댓글 저장하기
  4. 서버에 댓글 데이터 요청하기
  5. DB에서 댓글 데이터 가져와서 출력하기

 

댓글 기능 UI 만들기

Hint & Idea

  • 클라이언트 컴포넌트 사용하기
  • useState 사용하기

 

⬇정답 보기⬇

더보기
"use client";

import { useState } from "react";

export default function Comment() {

	const [comment, setComment] = useState("")

	return(
		<input type="text" value={comment} onChange={(e)=>{
        setComment(e.target.value)
        }}/>
	)
}

 

전송 버튼 누르면 댓글 데이터 서버에 전송하기

Hint & Idea

  • button 태그를 활용해서 전송 버튼 만들기
  • fetch를 통해 서버에 댓글 데이터 보내주기
  • fetch를 통해 서버에 어떤 글의 댓글인지 알 수 있는 데이터 보내주기

 

⬇정답 보기⬇

더보기
"use client";

import { useParams } from "next/navigation";
import { useState } from "react";

export default function Comment() {

	const [comment, setComment] = useState("")
    // URL에 나와있는 해당 글의 ID 값을 가져오기 위해 사용
    const params = useParams()

	return(
		<input type="text" value={comment} onChange={(e)=>{
        	setComment(e.target.value)
        	}}/>
        	<button onClick={()=>{
            // 데이터 전송하기 때문에 method는 POST,
            // body에는 댓글 내용과 어느 글의 댓글인지 알 수 있게 부모 글의 ID를 담는다.
        	fetch('서버 URL', {
        		method: 'POST',
        		body: JSON.stringify({comment, params})
        	})
        	setComment('')
         	}}>댓글 전송</button>
	)
}

 

받은 데이터 서버에서 확인하고 DB에 댓글 저장하기

Hint & Idea

  • button 태그를 활용해서 전송 버튼 만들기
  • fetch를 통해 서버에 댓글 데이터 보내주기
  • fetch를 통해 서버에 어떤 글의 댓글인지 알 수 있는 데이터 보내주기

 

⬇정답 보기⬇

더보기
import { connectDB } from "@/util/database";
import { getServerSession } from "next-auth";
import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { ObjectId } from "mongodb";

export default async function handler(req, res) {
    if (req.method == "POST") {
    	// JSON 데이터를 객체로 변환
        const { comment, params } = JSON.parse(req.body);
        
        // 현재 로그인되어 있는 유저 정보 가져오기
        let session = await getServerSession(req, res, authOptions);

        if (comment) {
            const db = (await connectDB).db("DB 이름");
            
            // 댓글 작성자, 댓글 내용, 부모 글의 ID를 DB에 저장
            db.collection("컬렉션 이름").insertOne({
                author: session.user.email,
                comment,
                
                // DB에 저장되는 형식을 맞추기 위해 ObjectID 사용
                parent: new ObjectId(params.id),
            });
            return res.status(200).json("저장 완료");
        } else {
            return res.status(500).json("댓글을 입력해주세요");
        }
}

 

서버에 댓글 데이터 요청하기

Hint & Idea

  • useEffect 사용하여 서버에 요청하기
  • fetch()로 get 요청하기
  • state에 받아온 데이터 저장하기

 

⬇정답 보기⬇

더보기
"use client";

import { useEffect, useState } from "react";

export default function Comment() {
	// 서버로부터 가져온 댓글 데이터를 저장
    const [allComment, setAllComment] = useState([]);
	
    // 컴포넌트가 처음 마운트될 때와 댓글 데이터가 추가되면 컴포넌트가 다시 마운트됨.
    // fetch를 사용해서 새로고침 없이 서버와 통신 가능
    useEffect(() => {
        // GET 요청을 처리하는 함수
        const fetchComments = async () => {
            try {
            	// query string을 통해 부모글의 ID 서버에 전달
                const response = await fetch(`/api/comment?id=${params.id}`);
            } catch (error) {
                console.error("댓글 데이터를 가져오는 중 오류 발생:", error);
            }
        };

        // 컴포넌트가 마운트될 때 GET 요청 실행
        fetchComments();
    }, [allComment]);

	(생략)
}

 

DB에서 댓글 데이터 가져와서 출력하기

Hint & Idea

  • server
    • 요청의 method 확인하기
    • query string으로 보낸 데이터 받기
    • 부모 글의 id를 통해 DB에서 데이터 가져오기
    • 가져온 데이터를 알맞는 형식으로 클라이언트 컴포넌트로 전달하기
  • client
    • 서버로부터 전달받은 데이터를 알맞은 형식으로 변환하기
    • 변환한 데이터를 state에 저장하기
    • map 함수를 통해 댓글 데이터 출력하기

 

⬇정답 보기⬇

더보기
import { connectDB } from "@/util/database";
import { getServerSession } from "next-auth";
import { ObjectId } from "mongodb";

export default async function handler(req, res) {
	(생략)
    else if (req.method == "GET") {
    	// query string으로 보낸 부모 글의 id 변수에 저장
        const id = req.query.id;
        const db = (await connectDB).db("DB 이름");
        const result = await db
            .collection("컬렉션 이름")
            // 부모 글의 ID로 그 글의 댓글 데이터를 가져오기
            .find({ parent: new ObjectId(id) })
            // 배열 형태로 만들기
            .toArray();
        // DB에서 가져온 데이터 클라이언트 컴포넌트에 전달하기
        return res.status(200).json(result);
    }
}
"use client";

import { useEffect, useState } from "react";

export default function Comment() {
	// 서버로부터 가져온 댓글 데이터를 저장
    const [allComment, setAllComment] = useState([]);
	
    // 컴포넌트가 처음 마운트될 때와 댓글 데이터가 추가되면 컴포넌트가 다시 마운트됨.
    // fetch를 사용해서 새로고침 없이 서버와 통신 가능
    useEffect(() => {
        // GET 요청을 처리하는 함수
        const fetchComments = async () => {
            try {
            	// query string을 통해 부모글의 ID 서버에 전달
                const response = await fetch(`/api/comment?id=${params.id}`);
                
                // 서버로부터 받아온 데이터를 json 형식으로 저장
                const data = await response.json();
                
                // 데이터를 state에 저장
                setAllComment(data);
            } catch (error) {
                console.error("댓글 데이터를 가져오는 중 오류 발생:", error);
            }
        };

        // 컴포넌트가 마운트될 때 GET 요청 실행
        fetchComments();
    }, [allComment]);

	    return (
        <div>
            <div>
            // map 함수를 활용해서 해당 글의 모든 댓글 출력하기
                {allComment.map((item, idx) => (
                    <div key={item._id}>
                        <p>{item.author}</p>
                        <p>{item.comment}</p>
                    </div>
                ))}
            </div>
            (생략)
        </div>
}
728x90