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

modric·2024년 12월 19일

Ok.. But why?

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

이 경고는 예전에 Serve actions로 몽고 디비 데이터에 대한 GET API구현할 때 마주쳤는데 갑자기! 왜 그래야만 하는가!.. 궁금해졌습니다.

경고는 서버 컴포넌트(Server Components)와 클라이언트 컴포넌트(Client Components) 간의 데이터 전달 메커니즘과 관련이 있습니다. 이 경고와 관련된 동작 원리와 원인을 아래에 설명합니다.

1. 동작 원리

서버 컴포넌트(Server Components)

서버 컴포넌트는 서버에서만 실행되며, 렌더링 결과를 직렬화된 형태(Serialized Form)로 클라이언트로 전송합니다.
이 직렬화된 데이터는 JSON 형식으로 표현되며, 클라이언트에서 복원(deserialize)되어 클라이언트 컴포넌트에서 사용됩니다.

클라이언트 컴포넌트(Client Components)

클라이언트 컴포넌트는 브라우저에서 실행되는 JavaScript 코드로, 서버로부터 전달받은 데이터를 기반으로 UI를 그립니다.
클라이언트 컴포넌트에 데이터를 전달할 때, 서버에서 직렬화가 가능하고, 브라우저에서 복원 가능한 순수 객체(Plain Object)만 사용할 수 있습니다.

2. 원인

JSON-직렬화와 순수 객체의 제약

  1. 직렬화 가능한 데이터만 허용:
  • 서버에서 클라이언트로 데이터를 전달할 때 JSON 형식으로 직렬화합니다. 따라서 JSON으로 직렬화할 수 없는 값은 허용되지 않습니다.
  • 예:
    • Date, Map, Set 같은 특수 객체
    • 함수수, 클래스 인스턴스, undefined
  1. React Server Components의 데이터 흐름 제한:
  • React 서버 컴포넌트는 특정 데이터 흐름을 강제하여 성능 최적화를 목표로 합니다. 직렬화가 불가능한 데이터를 전달하면 클라이언트에서 복원할 수 없기 때문에 이를 방지합니다.

순수 객체(Plain Object)란?

  • 순수 객체는 프로토타입이 없는 객체(예: {})로, JSON으로 직렬화가 가능한 객체입니다.
  • 순수 객체는:
    키/값 쌍으로 구성됨
    JavaScript 기본 데이터 타입만 포함 (string, number, boolean, array, null, object)

3. 왜 JSON 대신 다른 객체를 전달하면 안 되는가?

JSON 직렬화의 제한점

  • JSON은 JavaScript의 단순한 데이터 구조를 표현하기 위해 설계되었습니다.
  • 하지만 JavaScript의 다양한 데이터 구조(Date, Map, Set, 함수 등)는 JSON으로 표현이 불가능하거나 데이터가 손실됩니다.

React의 설계 철학

  • React 서버 컴포넌트는 데이터를 단순하고 안정적으로 처리하기 위해 JSON 직렬화를 강제합니다.
  • 이는 다음과 같은 이유 때문입니다:
    • 보안성:
      • 직렬화하지 않은 객체(특히 함수)는 보안 문제를 일으킬 수 있습니다.
      • 클라이언트에 민감한 데이터나 실행 코드가 포함될 가능성을 차단합니다.
    • 예측 가능성:
      • 순수 객체만 전달하면 데이터가 일관되고 예측 가능한 상태로 클라이언트에 전달됩니다.
    • 성능 최적화:
      - JSON 형식은 직렬화와 역직렬화가 빠르며, 브라우저와 서버 간 전송에 적합합니다.

      JSON의 장점

      1. 데이터 전송의 간소화 :
        JSON 형식은 텍스트 기반으로, 클라이언트와 서버 간에 데이터를 전송하기에 적합합니다. JSON은 텍스트 기반 포맷이므로 바이너리 데이터보다 크기가 작고, 네트워크 전송 속도가 빠릅니다.
        복잡한 데이터 구조를 지원하면 전송 크기가 증가하고 성능이 저하될 수 있습니다.
        직렬화된 데이터는 텍스트로 이루어져 있어 네트워크 전송 크기가 작고 속도가 빠릅니다.
        클라이언트에서 쉽게 역직렬화하여 사용할 수 있습니다.
      2. JSON의 단순성과 표준화
        JSON은 모든 프로그래밍 언어에서 지원하는 표준 포맷이기 때문에 호환성과 디버깅이 용이합니다.
        JSON 데이터를 읽고 쓰는 데 성능 오버헤드가 적습니다.
        브라우저의 JSON.parse와 JSON.stringify는 JavaScript 엔진에 최적화되어 매우 빠르게 처리됩니다.

4. 적절한 코드 예시

1) 데이터를 순수 객체로 변환

서버 컴포넌트에서 클라이언트 컴포넌트로 데이터를 전달하기 전에, JSON으로 변환 가능한 형태인지 확인해야 합니다.

// 서버 컴포넌트
function ServerComponent() {
  const data = {
    id: 1,
    name: "Example",
    date: new Date().toISOString(), // JSON에서 처리 가능한 형식으로 변환
  };

  return <ClientComponent data={data} />;
}

// 클라이언트 컴포넌트
function ClientComponent({ data }) {
  return <div>{data.name}</div>;
}

2) JSON으로 직렬화 불가능한 데이터를 따로 처리

Date, Map, Set 등을 클라이언트에서만 사용하도록 설계하거나, 전달하기 전에 JSON에 맞는 값으로 변환합니다.


// JSON 변환 가능하도록 처리
const date = new Date();
const plainData = {
  date: date.toISOString(), // 클라이언트에서 다시 new Date()로 복원 가능
};

3) 서버-클라이언트 분리 설계

복잡한 객체나 함수는 서버에서! 처리하고, 클라이언트로는 결과 데이터만 전달합니다.

5. 결론

React가 JSON 직렬화를 강제하는 이유는 성능 최적화, 예측 가능성, 표준화, 그리고 네트워크 전송 효율성을 유지하기 위해서입니다. React의 설계 철학인 단순성과 효율성을 지키기 위한 선택입니다.
순수 객체만 전달하는 제한은:

  • 직렬화 및 역직렬화 과정에서의 데이터 일관성
  • 클라이언트-서버 간 효율적이고 안전한 데이터 흐름
  • React 애플리케이션의 예측 가능성과 성능 최적화를 위한 것입니다.

이 경고를 해결하려면 순수 객체로 변환하거나, JSON으로 표현할 수 없는 데이터를 클라이언트에서 처리하도록 설계해야 합니다.

profile
안녕하세요 카페에서 코딩하면 안 일어나기 라는 일을 잘합니다

0개의 댓글