C.W.K.
Stream
Lesson 07 of 07 · published

RSC 경계 — 이 퀘스트가 punt 하는 이유

~11 min · rsc, server-components, next-js, boundary

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
React Server Components 는 실재 + 거대. 동시에 이 퀘스트에 없음. 이 레슨이 경계 설명 — next-js-quest 로 떠나는 시점을 정확히 알도록.

RSC 가 실제로 뭐

React Server Component = 렌더가 서버에서 (빌드 중 또는 요청마다) 도는 컴포넌트, 출력이 직렬화된 컴포넌트 트리로 클라이언트에 출하 — HTML 아니고, JavaScript 도 아님. 클라이언트 React 런타임이 그걸 Client Component 와 함께 마운트하고 interactive 부분만 hydrate.

큰 승리: static 부분에 JS 0 출하, 컴포넌트 안에서 직접 데이터 접근 (read-only fetch 에 API 레이어 필요 없음), '이건 서버에서 돔' 과 '이건 클라이언트에서 interactive 해야' 의 깨끗한 분할.

RSC 가 메타-프레임워크 필요한 이유

RSC 요구사항:

  1. React 돌리는 서버. (Vite dev server 안 돔.)
  2. 'use server'/'use client' 디렉티브 이해하고 모듈 그에 맞게 split 하는 빌드 파이프라인.
  3. 주어진 URL 에 어떤 RSC 렌더할지 아는 라우팅 레이어.
  4. 컴포넌트 트리 클라이언트로 스트리밍하는 직렬화 프로토콜.
  5. 그 프로토콜 소비할 줄 아는 클라이언트 런타임.

합쳐서 = 메타-프레임워크. Next.js 가 다섯 다 구현. Remix 스타일 프레임워크가 다섯 다 구현. Vite 단독은 하나도 구현 안 함 — Vite 는 dev server 가진 클라이언트 사이드 번들러, React 런타임 호스트가 아냐.

vite-plugin-rsc 는?

Vite 에서 RSC 탐험하는 실험적 플러그인들 있어. 지켜볼 가치 있음. 2026 중반 기준 프로덕션 ready 아님. 오늘 RSC 필요하면 Next.js 또는 Remix — 실험적 Vite 플러그인 아님.

Client Component 쪽은 여전히 여기 살아

React 19 가 클라이언트 사이드 동시성으로 소개한 모든 것 — useTransition, useDeferredValue, 클라이언트 사이드 promise 용 use() hook, React Compiler — 이 Vite SPA 에서 동작. 이 퀘스트에서 다 배워. Server Component 만 안 써 — 그걸 렌더할 런타임이 본인 스택에 없으니까.

특히 Server Action 은

Server Action 은 타입 시스템에선 React-19 primitive 지만, 실전에선 메타-프레임워크의 요청 처리에서 분리 불가. next-js-quest 에 나옴. 이 퀘스트에서 Action 다룰 때 (Track 6), 같은 useActionState/useFormStatus/useOptimistic hook 쓰지만 클라이언트 사이드 async 함수 (백엔드로 fetch, local storage 저장) 에 바인딩 — 서버 함수 아님.

핸드오프 지점. 이 퀘스트 끝내면 React 19 클라이언트 런타임을 처음부터 끝까지 이해. 그 토대로 next-js-quest 가면 RSC 가 '이 익숙한 컴포넌트들이 브라우저 대신 서버에서 돔' 으로 보임 — 새 프레임워크 통째로가 아니라. 분할은 실재, 개념적 간격은 작아.

Code

RSC 모양 (Next.js 문법, awareness 만)·tsx
// app/conversations/page.tsx — Next.js 의 Server Component
// 서버에서 돔. fetch 가 서버 사이드. API 레이어 필요 없음.
// 주목: 'use client' 디렉티브 없음. 기본이 서버.
import { db } from "@/lib/db";

export default async function ConversationsPage() {
  const conversations = await db.conversations.list();
  return (
    <ul>
      {conversations.map((c) => (
        <li key={c.id}>{c.title}</li>
      ))}
    </ul>
  );
}

// Vite SPA 에선 이거 못 짜. 렌더 중에 async 함수 실행할
// 서버 React 런타임이 없음.
Vite SPA 에서 Client Component 동등물 (이 퀘스트가 가르치는 것)·tsx
// src/pages/ConversationsPage.tsx — Vite SPA 의 client component
// 브라우저에서 돔. fetch + use() 로 데이터 로드 (Track 5).
import { use, Suspense } from "react";

async function fetchConversations() {
  const r = await fetch("/api/conversations");
  return (await r.json()) as Array<{ id: string; title: string }>;
}

function ConversationsList({ promise }: { promise: Promise<Array<{id:string;title:string}>> }) {
  const conversations = use(promise);
  return (
    <ul>
      {conversations.map((c) => (
        <li key={c.id}>{c.title}</li>
      ))}
    </ul>
  );
}

export function ConversationsPage() {
  const promise = fetchConversations();
  return (
    <Suspense fallback={<p>Loading…</p>}>
      <ConversationsList promise={promise} />
    </Suspense>
  );
}

// 같은 결과 (conversation 리스트). 다른 런타임 스토리.
// SEO/initial-payload 차이 — RSC 는 HTML 출하; 이건 JS 출하 + 런타임에 fetch.

External links

Exercise

본인 현재 Vite SPA 프로젝트 (또는 갖고 있는 아이디어) 가 RSC 로 얻을 feature 셋 나열. 그 다음 여전히 Vite SPA 고를 이유 셋 나열. 목표는 하나 고르는 게 아냐 — 본인 말로 trade-off 를 verbalize 해서 다음 프로젝트 시작할 때 의식적 선택이 되는 것.
Hint
RSC 승: SEO, 작은 JS 번들, 직접 DB 쿼리, read 용 API 레이어 없음. Vite SPA 승: 더 단순한 배포 (어떤 static host), Node 런타임 운영 안 함, Tauri/Electron/임베디드 컨텍스트 안에서 동작, 풀 클라이언트 사이드 state 모델.

Progress

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

댓글 0

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

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