게시물 목록에서 특정 게시물의 삭제 버튼을 누르면 해당 글이 삭제되는 기능 구현 중 이 같은 에러가 발생하였다.

 

 

데이터베이스에서 게시물 데이터를 삭제하려면 해당 게시물의 id값을 넘겨줘야 어떤 항목을 삭제할지 알 수 있으므로, 위와 같이 request body에 id를 넘겨주려 시도하였다. 서버에 Object나 Array를 넘겨줄 때는 JSON.stringify()를 사용하여 문자열 형식으로 보내줘야 하기 때문에 저렇게 작성한 것이었는데, 이 부분(정확히는 해당 요청을 받는 부분)에서 문제가 발생한 것을 알게 되었다.

// /app/list/ListItem.js

export default function ListItem({ data }) {
  return (
  	// ...
    <button
      onClick={() =>
        fetch("/api/post/delete", {
          method: "DELETE",
          body: JSON.stringify({ _id: data._id}),
      }).then(() => {
        console.log("테스트");
      }).catch((error) => {
        console.error("에러:", error);
      })
    // ...
}>
// /pages/api/post/delete.js

export default async function handler(request, response) {
  if (request.method == "DELETE") {
    console.log(request.body);
    try {
      const db = (await connectDB).db("forum");
      const filter = { _id: new ObjectId(request.body._id) }
      const data = await db.collection("post").deleteOne(filter);
      return response.status(200).json(data + "삭제");
    } catch (error) {
      return response.status(500).json("DB 삭제 실패");
    }
  }
}

 

 

에러 문구를 해석해보면

Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value before passing it to props.

 

클라이언트 컴포넌트에서 서버 컴포넌트로 전달 시 plain object만 가능하며, JSON으로 변환해주는 메소드를 지원하지 않으니, props로 전달하기 이전에 단순한 데이터(문자열 혹은 숫자 등)으로 직접 바꾸라고 하고 있다.

내 코드에서는 plain object가 아닌 ObjectId 객체를 서버에 전달하고 있음으로, 해당 오류가 뜬 것 같다. 

 

이에 대해 두 가지 해결 방안이 존재한다.

 

1.

애초에 서버 컴포넌트로 게시물의 id값을 넘겨줄 때, { _id: data._id } 와 같이 객체를 그대로 넘겨줄게 아니라 단순히 id값만(data._id) 전달해주면 된다.

fetch("/api/post/delete", {
	method: "DELETE",
	body: data._id,
})

실제로 이렇게 전달 시 요청을 받은 서버에서는 request.body를 콘솔에 찍어봤을 때 선택한 게시물 데이터의 id값이 출력되는 것을 확인할 수 있다.

 

 

2.

서버에 object나 array를 보낼 때는 JSON.stringify()를 사용하라고 했다. (서버와 데이터를 주고 받을 때는 문자나 숫자만 가능하기 때문)

해당 메소드 사용 시 원래 object가 { _id: 123 } 이었다고 할 때, JSON.stringify({ _id: 123 })는

{ "_id": 123 }

이와 같이 JSON 형식으로 변환된다.

 

따라서, . 연산자를 사용하여 객체의 값에 접근하는 것이 불가능해진다.

1번 방법과 다르게 나는 그냥 보낼 때 object형으로 보내고, 받을 때 request.body._id 해서 받으면 되는거 아니야?라고 생각할 수 있는데, 그게 불가능하다는 뜻이다.

고로 서버에 전달될 때 JSON형으로 바꿨던 데이터를 다시 Object형으로 바꿔주어야 하는데, 이는 JSON.parse()를 사용하면 된다.

결과적으로 JSON.parse(request.body)._id 와 같이 작성하면 ObjectId를 보내도 그 안에서 id값만 뽑아내어 사용할 수는 있게 되는 것이다. (고로 처음에 작성했던 대로 요청을 보내려면 서버 컴포넌트에서의 코드를 아래와 같이 수정해줘야 된다)

// 서버에 요청 시 데이터도 함께 전달
fetch("/api/post/delete", {
  body: JSON.stringify({ _id: data._id}),
})

// 서버 컴포넌트에서 요청을 받을 때
const data = await db.collection("post").deleteOne(JSON.parse(request.body)._id);

 

 

 


참고 :

https://velog.io/@developer-jyyun/Warning-Only-plain-objects-can-be-passed-to-Client-Components-from-Server-Components

 

Warning: Only plain objects can be passed to Client Components from Server Components.

errWarning: Only plain objects can be passed to Client Components from Server Components.클라이언트 컴포넌트에 plain object가 아닌 객체(예: ObjectId 객체)를 전달하려고 했기 때문에

velog.io

 

해안해