RSC 도입 이후, SSR은 어떻게 달라졌을까?

바다·2025년 2월 18일
0

react

목록 보기
11/11
post-thumbnail

🤯 "SSR을 처음 배울 때는 서버가 HTML을 보내준다고 배웠는데,이제는 RSC Payload를 보낸다고?"

🤔 "Next.js는 Streaming Rendering을 지원한다는데,그럼 Streaming SSR이랑은 또 뭐가 다르지?"

🫠 "Streaming HTML도 관련이 있다는데… 뭐가 뭔데?!"

처음엔 머릿속이 뒤죽박죽이었다.
하지만 React Server Components(RSC) 이전과 이후의 SSR을 정리하고 나니,이제야 비로소 퍼즐이 맞춰지기 시작했다.

SSR의 흐름

비교 항목React 17까지 (SSR)React 18 (Streaming SSR)React 18 (RSC 적용 SSR)
서버 출력완전한 HTMLHTML을 Chunk로 스트리밍RSC Payload
클라이언트 HydrationHTML + JS 번들 다운받고 실행HTML Streaming 후 JS 실행RSC Payload 역직렬화 + 필요한 JS 실행
서버의 데이터 패칭서버에서 미리 가져와서 HTML로 생성일부 HTML 먼저 보내고, 나머지 점진적으로 로딩RSC에서 개별적으로 패칭
JS 번들 최적화클라이언트에서 모든 JS 포함클라이언트에서 모든 JS 포함RSC는 서버에서 실행하므로 불필요한 JS 제거
Streaming 지원❌ 없음✅ HTML Streaming 가능✅ RSC Streaming 가능

SSR는 위의 표처럼 React17까지의 전통적인 SSR,Streaming SSR, 서버 컴포넌트를 적용한 SSR으로 변해갔다. 왜 SSR의 방식은 변해갔을까?

전통적인 SSR (React 17까지)

✨등장 배경

클라이언트에서 모든 렌더링을 수행하면, 초기 HTML이 비어 있고, JS 번들을 다운로드·파싱·실행한 후에야 화면이 그려져 첫 화면 로딩이 느린 문제가 있다. 이를 해결하기 위해 서버에서 HTML을 렌더링해서 미리 보내는 방식(SSR) 등장했다.

🚨문제

  • 서버에서 모든 HTML을 다 생성하고 나서야 클라이언트에게 전송해주기 때문에 응답 속도가 느리다.
  • 클라이언트에서 Hydration(상태 복구)까지 끝나야 인터랙션 가능하다
  • JS 번들 크기가 크면 로드 시간이 길어진다

➡️ 사용자 경험을 저하한다
➡️ 그럼 서버에서 HTML을 한 번에 보내지 않고, 점진적으로 보내면 어떨까?

Streaming SSR (React 18)

✨이전 SSR 문제 해결

HTML이 완전히 준비될 때까지 사용자가 빈 화면을 보며 기다려야 하는 기존 SSR문제를 해결하기 위해서 등장했다. HTTP Header로 제공되는 Streaming HTML을 적용해, HTML 청크로 나누어서 준비가된 HTML부터 점진적으로 클라이언트에게 전달한다.

🚨문제

이전 SSR보다 초기 렌더링 속도가 빨라졌으나, 브라우저에서 렌더링 되지 않아도 될 컴포넌트들이 JS번들에 여전히 들어있어 JS번들 로드 속도는 여전히 크다.

➡️ 서버에서 실행 가능한 로직을 더 활용할 순 없을까?
➡️ 서버에서 실행할 컴포넌트와 클라이언트에서 실행할 컴포넌트를 분리해자!

RSC를 적용한 React 18 이후 SSR

✨React Server Components(RSC) 적용

서버

  • 서버에서만 실행되는 컴포넌트인 RSC는 서버에서 실행되어, 직렬화된 RSC Payload로 클라이언트에게 전달
  • 클라이언트 컴포넌트(RCC)는 JS 번들이 필요하므로 따로 제공
  • 비동기로 동작하는 RSC에 Suspense를 같이 사용하면 비동기 작업이 완료된 RSC Payload를 점진적으로 전달

클라이언트

  • RSC Payload를 역직렬화하여 React 트리로 변환
  • 필요한 JS를 로드하고, 클라이언트에서 실행될 RCC를 Hydration하여 렌더링

Streaming Rendering?
React의 Streaming Rendering은 기존 Streaming SSR보다 한 단계 더 발전된 방식으로, React Server Components(RSC)와 Suspense를 활용하여 부분적으로 UI를 렌더링할 수 있도록 최적할 수 있다.

위의 gif는 무한 스크롤을 적용한 검색 페이지로, 스크롤 시 도서들이 추가된면서 해당 RSC Payload가 추가되고 있다.

RSC Payload

RSC Payload인 이유

여기서 궁금한게 생겼다. 렌더링 속도 측면에서는 HTML을 보내는 것이 나을텐데 왜 서버 컴포넌트는 RSC Payload라는 방식으로 클라이언트에게 전달될까?

1. 번들 크기 최소화

RSC Payload는 React만의 컴포넌트 직렬화 방식이다. 클라이언트에서 실행할 필요가 없는 서버 컴포넌트를 서버에서 실행해, 그 결과물을 직렬화한다. JS번들에는 클라이언트에서 실행하는 것만 담기에 되어 JS 번들 크기가 줄어든다.

또한 클라이언트는 서버 컴포넌트에 대한 Hydration을 진행할 필요없이 RSC Payload를 UI로 변환할 수 있다.

🔍 RSC Payload 살펴보기

  • RSC Payload는 ~_rsc라는 파일명으로 전달된다.
  • RSC Paload를 살펴보면,DOM트리의 어느 부분에서 열리는지와 key값등을 확인할 수있다.

💡 프리패칭 시, 정적/동적 페이지 비교

  • 정적 페이지를 프리패칭한다면 RSC Payload와 JS 번들을 둘 다 받는다
  • 동적 페이지를 프리패칭한다면 RSC만 받는다

위의 사진 속 프로젝트에서 동적 페이지인 인기 대출 도서 페이지는 프리패칭된다. 개발자 도구의 네트워크 탭을 살펴보면popular?_rsc라는 RSC Payload를 전달받고 있다는 것을 발견할 수 있다.

2. React의 Composition 철학 유지 (HTML보다 유연한 렌더링)

HTML을 보내는 기존의 SSR 방식에서는 컴포넌트 트리를 다루기가 어려웠다. 서버 컴포넌트가 등장하고 서버는 RSC Payload를 전달하고 클라이언트는 클라이언트 컴포넌트 렌더링에 필요한 JS를 처리하게 되면서 서버와 클라이언트가 컴포넌트 단위로 협업이 가능해졌다.

서버 컴포넌트(RSC)와 클라이언트 컴포넌트(RCC)

RCC에서 RSC를 직접 import해서 사용할 수 있을까?

서버 컴포넌트에서 클라이언트 컴포넌트를 직접 import할 수 있지만, 그 반대를 할 수 없다. 서버 컴포넌트는 서버에서 실행되어야하는데, 클라이언트 컴포넌트에거 이를 직접 import하면 서버 컴포넌트는 JS 번들에 포함되어 서버가 아닌 브라우저에서 실행되어진다.

그렇다면 클라이언트 컴포넌트 하위에 서버 컴포넌트를 두려고 한다면 어떻게 해야할까?

그럴 때는 클라이언트 컴포넌트에서 children으로 서버 컴포넌트를 받고 이를 상위의 서버 컴포넌트에서 선언해줘야한다.

// ✅ 상위 서버 컴포넌트 또는 페이지 (page.tsx)
import ClientComponent from "@/components/ClientComponent";
import ServerComponent from "@/components/ServerComponent";

export default function Page() {
  return (
    <div>
      <h1>Next.js RSC + RCC 올바른 사용 예제</h1>
      {/* ✅ RCC가 RSC를 children으로 받아서 실행 */}
      <ClientComponent>
        <ServerComponent />
      </ClientComponent>
    </div>
  );
}

RSC의 props는 RCC에게 어떻게 전달되는거지?

클라이언트에서 RSC Payload를 받아 UI를 복원하면서 클라이언트 컴포넌트가 있는지 감지해 필요한 JS 번들을 로드하여 Hydration 진행하게 된다. 이 과정에서 클라이언트 컴포넌트가 서버 컴포넌트로부터 받아야하는 Props를 RSC Payload로 부터 전달받는다.

단! 직렬화 할 수 없는 함수 등은 RSC Payload에 담기지 않기 때문에 이를 클라이언트 컴포넌트에 props로 내려줄 수 없다
서버에서 실행하는 함수가 필요하다면 서버 액션 함수를 선언해 클라이언트 컴포넌트에서 이를 import해서 사용할 수 있다.

profile
🐣프론트 개발 공부 중 (우테코 6기)

0개의 댓글

관련 채용 정보