C.W.K.
Stream
Lesson 06 of 08 · published

Serialization Boundary

~22 min · serialization, props, boundary

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

경계 넘을 수 있는 것

Server Component 가 Client Component 에 prop 넘기면, data 가 serialize 돼야 해. Boundary 가 대략 "JSON 모양 + React extra 몇 개".

허용 ✅차단 ❌
String, number, booleanFunction
Array, plain objectClass instance
Date (string 으로 serialize)Symbol
null / undefinedDOM node / stream
FormDataCircular reference
React element (JSX) 와 Promise

큰 결과

Server 에서 client 로 function 못 넘김. Client 가 server logic 으로 callback 하고 싶으면 Server Action 정의하고 그걸 내려 (framework 가 serialized POST endpoint reference 로 wrap).

Composition 의 trick

JSX element 가 serialize 됨. 그래서 Server Component 가 다른 Server Component 를 children 으로 Client Component 한테 넘길 수 있음 — Client Component 가 render 만 하고 import 안 함. Server-rendered subtree 를 client-side interactivity 로 wrap 하는 가장 깔끔한 방법.

Code

Serializable prop 넘기기·tsx
// app/page.tsx — Server
import { LikeButton } from '@/components/LikeButton';

export default async function Page() {
  const post = await getPost();
  return (
    <article>
      <h1>{post.title}</h1>
      {/* ✅ string + number — serializable */}
      <LikeButton postId={post.id} initialCount={post.likes} />

      {/* ❌ Function 못 넘김 — compile 안 됨 */}
      {/* <LikeButton onLike={() => handleLike()} /> */}
    </article>
  );
}
Client 가 plain prop 받음·tsx
'use client';
import { useState } from 'react';

export function LikeButton({
  postId,
  initialCount,
}: {
  postId: string;
  initialCount: number;
}) {
  const [count, setCount] = useState(initialCount);
  return (
    <button onClick={() => setCount(c => c + 1)}>♥ {count}</button>
  );
}
Server JSX 를 children 으로 넘김·tsx
// app/page.tsx — Server
import { Accordion } from '@/components/Accordion';
import { ProductDetails } from '@/components/ProductDetails';

export default async function Page() {
  const product = await getProduct();
  return (
    <Accordion>
      {/* Server-rendered subtree 를 Client wrapper 로 */}
      <ProductDetails product={product} />
    </Accordion>
  );
}

// components/Accordion.tsx — Client
'use client';
import { useState } from 'react';

export function Accordion({ children }: { children: React.ReactNode }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => setOpen(!open)}>Toggle</button>
      {open && children}
    </>
  );
}

External links

Exercise

Callback prop 받는 Client Component 골라. Callback 을 Server Action 으로 (나중에 다룸) 또는 children pattern 으로 교체. Rewrite 가 boundary 어떻게 개선했는지 문서화.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.