본문 바로가기
C.W.K.
Stream
Lesson 07 of 07 · published

RSC 경계 — 이 퀘스트에서 다루지 않는 이유

~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는 중요한 기술이지만 이 Vite SPA 퀘스트의 범위는 아니야. 어디까지가 React이고 어디서부터 프레임워크의 책임인지 경계를 세워 보자.

RSC가 실제로 하는 일

React Server Component는 빌드할 때나 요청을 받을 때 서버에서 렌더링되는 컴포넌트야. 그 결과는 HTML이나 일반 JavaScript가 아니라 직렬화된 컴포넌트 트리로 클라이언트에 전달돼. 클라이언트의 React 런타임은 그 결과를 Client Component와 합치고, 상호작용이 필요한 부분만 hydrate해.

장점은 분명해. 정적인 부분에는 클라이언트 JavaScript를 보내지 않아도 되고, 읽기 전용 데이터라면 컴포넌트에서 서버 데이터에 직접 접근할 수 있어. 서버에서 실행할 코드와 브라우저에서 상호작용할 코드의 경계도 명확해져.

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

RSC를 실행하려면 다음 다섯 가지가 함께 필요해.

  1. React를 실행할 서버.
  2. 'use server''use client'를 이해하고 모듈을 나눌 빌드 파이프라인.
  3. URL에 맞는 RSC 트리를 고를 라우팅 계층.
  4. 컴포넌트 트리를 클라이언트로 보낼 직렬화 프로토콜.
  5. 그 프로토콜을 읽을 클라이언트 런타임.

이 요소를 한데 제공하는 것이 메타 프레임워크야. Next.js와 Remix 계열 프레임워크는 이 책임을 맡지만, Vite 단독은 그렇지 않아. Vite는 빠른 개발 서버와 클라이언트 번들러를 제공할 뿐 React 서버 런타임을 호스팅하지는 않아.

vite-plugin-rsc는?

Vite에서 RSC를 실험할 수 있는 플러그인은 있어. 지켜볼 가치는 있지만 2026년 중반 기준으로 이 퀘스트가 권할 프로덕션 선택지는 아니야. 지금 RSC가 필요하다면 실험적 플러그인보다 Next.js나 Remix 계열 프레임워크를 선택해.

클라이언트 기능은 여전히 이 퀘스트의 범위야

useTransition, useDeferredValue, 클라이언트 프로미스를 읽는 use(), React Compiler처럼 React 19가 제공하는 클라이언트 기능은 이 Vite SPA에서도 동작해. 이 퀘스트는 그 기능을 모두 다뤄. 제외하는 것은 Server Component뿐이야. 선택한 스택에 그것을 렌더링할 서버 런타임이 없기 때문이지.

서버 액션과의 경계

Server Action은 React 19의 기본 요소지만, 실제 앱에서는 메타 프레임워크의 요청 처리와 분리하기 어려워. 자세한 내용은 next-js-quest에서 다뤄. Track 6에서는 같은 useActionState, useFormStatus, useOptimistic 훅을 사용하되, 백엔드에 fetch하거나 로컬 저장소를 갱신하는 클라이언트 비동기 함수에 연결해. 서버 함수로 실행하는 건 아니야.

다음 퀘스트로 넘어가는 지점: 이 퀘스트를 끝내면 React 19의 클라이언트 런타임을 처음부터 끝까지 이해하게 돼. 그 상태에서 next-js-quest로 가면 RSC는 완전히 낯선 체계가 아니라, 익숙한 컴포넌트를 브라우저 대신 서버에서 실행하는 구조로 보일 거야. 실행 경계는 실제로 다르지만 개념의 간격은 크지 않아.

Code

Next.js 문법으로 RSC 경계 살펴보기·tsx
// app/conversations/page.tsx — Next.js의 서버 컴포넌트
// 서버에서 실행돼. 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에서는 이렇게 작성할 수 없어. 렌더링 중 비동기 함수를 실행할
// 서버 React 런타임이 없기 때문이야.
Vite SPA에서 같은 화면을 클라이언트 컴포넌트로 만들기·tsx
// src/pages/ConversationsPage.tsx — Vite SPA의 클라이언트 컴포넌트
// 브라우저에서 실행돼. 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는 서버 결과를 보내고, 이 코드는 JS를 보낸 뒤 런타임에 fetch해.

External links

Exercise

만들고 싶은 프로젝트 하나를 골라 RSC가 주는 이점과 Vite SPA가 주는 이점을 각각 세 가지 이상 적어. 공개 콘텐츠와 SEO, 첫 JavaScript 크기, 서버의 직접 데이터 읽기, 정적 배포, Node runtime 운영, Tauri 같은 데스크톱 환경, 클라이언트 상태를 실제 요구에 대입한 뒤 하나를 선택해.
Hint
목표는 정답을 외우는 게 아니라 결정 근거를 말할 수 있게 되는 거야. TTFB와 검색 유입이 중요한 공개 화면인지, 로그인 뒤 오래 쓰는 상호작용 중심 도구인지부터 구분해.

Progress

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

댓글 0

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

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