React/프론트엔트 개념 정리

Next.js에서 RSC 방식이란?(feat.서버, 클라이언트 컴포넌트)

연신내고독한늑대 2025. 10. 27. 14:59

Next.js 13부터 도입된 App RouterRSC (React Server Component) 개념은 처음 접했을 때 꽤나 헷갈립니다.
저도 최근 작은 프로젝트를 하면서 "이걸 어떻게 구조화하지?", "fetch는 어디서 해야 하지?" 같은 고민을 정말 많이 했어요.

그 과정에서 직접 부딪히며 느꼈던 시행착오들을 공유하려고 합니다. 아래의 폴더 구조를 파악해서 예시 코드를 보시면 이해 하기 수월합니다!

## 폴더 구조
/src
  ├── app                  # Next.js의 App Router
  │   ├── api/apiName      # 서버에서만 동작하는 API Route (route.ts)
  │   └── pageName         # 사용자에게 보여줄 페이지들 (page.tsx)
  ├── lib
  │   ├── server           # 서버 컴포넌트에서 직접 사용하는 서버 로직
  │   └── client           # 클라이언트 컴포넌트에서 fetch로 API 호출하는 로직
  *lib/server 같은 경우 Prisma, fs, process.env 등 서버 전용 코드를 사용하기 때문에 클라이언트(브라우저)에서 실행 될 경우 오류 발생
  
  위 구조는 제가 직접 사용한 폴더 구조입니다. 
  서버용 코드와 클라이언트용 코드를 구분하였습니다.

 

■ RSC 방식이란?

RSC(React Server Components) = 서버에서 실행되는 React 컴포넌트

Next.js에서는 기본적으로 page.tsx가 서버 컴포넌트입니다.

즉, 이곳에서 API 호출을 하거나 DB에 직접 접근하는 게 가능합니다.

// 서버 컴포넌트 (app/gift/update/page.tsx)
import { getGiftData } from '@/lib/server/gift';

export default async function GiftPage() {
  const data = await getGiftData(); // ✅ 직접 DB 접근 가능!
  return <ClientComponent data={data} />;
}

 

  • 이처럼 서버 컴포넌트에서는 lib/server에 있는 서버 전용 로직을 불러와 직접 실행할 수 있습니다.
  • fetch나 /api를 거칠 필요 없이 곧바로 Prisma 등 DB 호출이 가능합니다.

서버 컴포넌트 안에는 클라이언트 컴포넌트를 사용 할 수 있어서 서버 클라이언트에서 데이터를 받아서 props로 전달 할 수 있습니다. 하지만 그 반대 상황인 클라이언트 컴포넌트('use client')에서 서버 컴포넌트를 호출 할 수 없니다. 그 이유는 클라이언트 컴포넌트는 브라우저에서 실행되기 때문에, 직접 DB 접근은 불가능

// GiftForm.tsx (클라이언트 컴포넌트)
'use client'

import { getGiftData } from '@/lib/server/gift';

export default function GiftForm() {
  // ❌ 서버 함수는 클라이언트에서 호출 불가
  // 🔴 Error: Cannot serialize a function returned from server
}

 

→ 이럴 때는 아래와 같이 클라이언트 컴포넌트에서는 lib/client → fetch → app/api → lib/server(게시글 초기 폴더 구조 확인)를 거쳐야 합니다.

// lib/client/gift/getGift.ts
export async function getGift() {
  const res = await fetch('/api/gift/getGift');
  const json = await res.json();
  return json;
}

// 'use client' 컴포넌트
'use client';
import { getGift } from '@/lib/client/gift/getGift';

useEffect(() => {
  getGift().then((res) => {
    // 응답 처리
  });
}, []);

■ 요약

구분 사용 위치 동작 방식
lib/server 서버 컴포넌트, API 직접 DB접근 가능
lib/client 클라이언트 컴포넌트 직접 DB접근 불가능 하므로 fetch사용
/app/api/** Api route(API 전용) lib/server 함수 불러서 사용 가능
page.tsx(서버 컴포넌트가 default) 초기 랜더링 시 DB접근 lib/server 함수 직접 호출
use client 이벤트 발생 후 데이터 요청 lib/client에 접근 하여 api 사용

■ 결론

Next.js에서 **RSC 방식은 서버에서 먼저 데이터를 준비해서 화면을 그려주는 방식**
그래서 페이지 초기 렌더링(특히 GET 방식)에 적합하고, 클라이언트에서 발생하는 액션(예: 버튼 클릭, 전송, 수정)은 기존처럼 fetch를 통해 API를 호출하여 사용합니다.