PromleeBlog
sitemap
aboutMe

posting thumbnail
React 렌더링 방식 이해하기 (SSR, SSG, Hydration) - React, 알고 쓰자 7일차
Explained Understanding React Rendering (SSR, SSG, Hydration) - React Explained Day 7

📅

🚀

들어가기 전에 🔗

우리는 지금까지 React를 사용하여 동적인 사용자 인터페이스를 만드는 방법에 집중해왔습니다.
기본적으로 React 애플리케이션은 사용자의 브라우저에서 JavaScript를 실행하여 화면을 그리는
클라이언트 사이드 렌더링(Client-Side Rendering, CSR)
방식으로 동작하는 경우가 많습니다.
CSR은 풍부한 상호작용을 제공하지만, 초기 로딩 시 사용자가 빈 화면을 보게 되거나 검색 엔진 최적화(SEO)에 어려움을 겪는 단점이 있을 수 있습니다.
이러한 단점을 보완하기 위해 등장한 것이 바로 *서버 사이드 렌더링(Server-Side Rendering, SSR)*과 *정적 사이트 생성(Static Site Generation, SSG)*입니다.
오늘은 이 다양한 렌더링 방식들이 각각 어떻게 동작하고 어떤 특징을 가지는지, 그리고 이들과 밀접하게 관련된
Hydration
이라는 개념은 무엇인지 자세히 알아보겠습니다.

🚀

CSR: Client-Side Rendering 🔗

먼저 우리가 가장 익숙한 방식인 클라이언트 사이드 렌더링(CSR)을 간단히 알아보겠습니다.

동작 방식 🔗

  1. 사용자가 웹사이트에 접속하면 브라우저는 최소한의 HTML 파일과 JavaScript 번들 파일을 다운로드합니다.
  2. 브라우저는 다운로드한 JavaScript를 실행합니다.
  3. JavaScript(React 코드)가 실행되면서 가상 DOM을 만들고, 실제 DOM을 조작하여 화면에 UI를 그립니다.
  4. 이후 사용자 상호작용에 따라 JavaScript가 계속해서 UI를 업데이트합니다.

장점 🔗

단점 🔗


🚀

SSR: Server-Side Rendering 🔗

서버 사이드 렌더링(SSR)은 CSR의 초기 로딩 및 SEO 단점을 해결하기 위해 등장한 방식입니다.
SSR은 이름 그대로, 웹 페이지 내용을
서버 측에서 미리 렌더링
하여 완성된 HTML 형태로 클라이언트(브라우저)에게 전달하는 방식입니다.

동작 방식 🔗

  1. 사용자가 웹사이트에 접속하면 브라우저는 서버에 페이지를 요청합니다.
  2. 서버는 요청받은 페이지에 필요한 데이터(API 호출 등)를 가져와서, React 컴포넌트를 렌더링하여 완전한 HTML 문자열을 생성합니다.
  3. 서버는 이 완성된 HTML을 브라우저에게 응답으로 보냅니다.
  4. 브라우저는 서버로부터 받은 HTML을 즉시 화면에 표시합니다 (사용자는 콘텐츠를 빠르게 볼 수 있음).
  5. 동시에 브라우저는 필요한 JavaScript 번들 파일을 백그라운드에서 다운로드합니다.
  6. JavaScript 로딩이 완료되면, React가 실행되어 서버에서 생성된 정적 HTML 위에 이벤트 핸들러 등을 연결하여 상호작용 가능한 상태로 만듭니다 (이 과정을
    Hydration
    이라고 합니다. 잠시 후 자세히 알아볼게요).
CSR과 SSR의 초기 로딩 과정을 비교
CSR과 SSR의 초기 로딩 과정을 비교

CSR과의 비교 🔗

Next.js와 스트리밍 SSR 🔗

전통적인 SSR은 서버에서 페이지 전체 HTML 생성이 완료될 때까지 기다렸다가 응답을 보내므로, 페이지가 복잡하거나 데이터 로딩이 오래 걸리면 TTFB가 느려지는 단점이 있었습니다.
이를 개선하기 위해
스트리밍 SSR(Streaming SSR)
이라는 기술이 등장했습니다.
Next.js의 App Router (app 디렉터리 방식)는 기본적으로 스트리밍 SSR을 지원합니다.

🚀

SSG (Static Site Generation) 🔗

정적 사이트 생성(SSG)은 웹사이트의 모든 페이지를
빌드 시점
에 미리 HTML 파일로 생성해두는 방식입니다.

동작 방식 🔗

  1. 개발자는 코드를 빌드(build)합니다.
  2. 빌드 과정에서 프레임워크(예: Next.js, Gatsby)는 정의된 모든 경로에 대해 페이지를 미리 렌더링하고, 각각을 별도의 HTML 파일로 생성합니다. (필요한 데이터도 빌드 시점에 가져옵니다)
  3. 생성된 HTML, CSS, JavaScript 파일들은 정적 파일 서버나 CDN(Content Delivery Network)에 배포됩니다.
  4. 사용자가 특정 페이지를 요청하면, 서버는 이미 만들어진 해당 HTML 파일을 즉시 사용자에게 전송합니다.
  5. CSR과 마찬가지로, 브라우저는 HTML을 표시한 후 JavaScript를 로드하여 페이지를 상호작용 가능하게 만듭니다 (Hydration).

CSR/SSR과의 비교 🔗

언제 사용하면 좋을까요? 🔗

SSG는 콘텐츠가 자주 변경되지 않고, 빌드 시점에 모든 페이지를 생성할 수 있는 경우에 매우 효과적입니다.
Q: "SSR과 SSG의 차이점은 무엇이고, 각각 언제 사용하는 것이 좋을까요?"
A: "SSR은 요청 시 서버에서 HTML을 생성하고, SSG는 빌드 시 HTML을 미리 생성합니다. SSR은 사용자별 동적 콘텐츠나 매우 자주 바뀌는 데이터에 적합하고, SSG는 정적 콘텐츠 위주의 사이트에서 최고의 성능을 제공합니다."

🚀

Hydration: 서버에서 생성된 HTML을 동적으로 만드는 과정 🔗

SSR이나 SSG로 생성된 HTML은 처음에는 그저 '보여주기만 하는' 정적인 문서입니다. 사용자가 버튼을 클릭하거나 입력하는 등의 상호작용을 하려면 JavaScript(React)가 필요합니다.
Hydration
은 서버에서 생성된 정적 HTML 위에 클라이언트 측 JavaScript(React)를 실행하여, 마치 물을 뿌려 마른 땅을 적시듯(hydrate) 상호작용이 가능한 동적인 애플리케이션 상태로 만드는 과정을 의미합니다.

왜 필요할까요? 🔗

Hydration 과정에서 React는 다음과 같은 중요한 작업들을 수행합니다.
즉, Hydration은 서버가 만들어준 '뼈대(HTML)'에 React라는 '신경망과 근육(JavaScript)'을 연결하여 살아 움직이는 애플리케이션으로 완성하는 과정입니다.

주의할 점: Hydration 에러 🔗

Hydration 과정에서 React는 서버에서 렌더링된 HTML 구조와 클라이언트에서 렌더링하려는 가상 DOM 구조가
정확히 일치
할 것으로 기대합니다.
만약 두 구조 사이에 불일치가 발생하면, React는 Hydration을 제대로 수행할 수 없다는 경고(Hydration Mismatch Error)를 표시하고, 경우에 따라 클라이언트 측에서 전체를 다시 렌더링하게 되어 SSR/SSG의 이점을 잃을 수도 있습니다.
이런 불일치는 주로 다음과 같은 경우에 발생할 수 있습니다.
이런 오류를 피하려면 서버와 클라이언트에서 렌더링 결과가 일관되도록 코드를 작성하는 것이 중요합니다. 필요한 경우 useEffect 등을 사용하여 클라이언트에서만 실행되어야 하는 로직을 분리해야 합니다.

🚀

진화하는 렌더링 패턴 🔗

최근 프론트엔드 커뮤니티에서는 SSR/SSG의 장점을 살리면서도 JavaScript 로딩 및 실행 비용을 줄이기 위한 새로운 패턴들이 주목받고 있습니다.

부분 Hydration (Partial Hydration) 🔗

페이지 전체를 한 번에 Hydration 하는 대신, 상호작용이 필요한
일부 컴포넌트만
선택적으로 Hydration 하는 방식입니다.
정적인 부분은 HTML로 남겨두고, 동적인 부분만 JavaScript를 로드하여 실행하므로 초기 로딩 및 상호작용까지의 시간(Time to Interactive, TTI)을 단축할 수 있습니다.

아일랜드 아키텍처 (Islands Architecture) 🔗

부분 Hydration 개념을 기반으로, 웹 페이지를 정적인 HTML '바다' 위에 떠 있는 여러 개의 상호작용 가능한 '섬(Island)'들로 구성하는 아키텍처 패턴입니다.
각 '섬'은 독립적인 위젯 또는 컴포넌트이며, 자체적으로 스크립트를 로드하고 Hydration을 수행합니다.
➡️

장점 🔗

각 컴포넌트(섬)가 필요한 JavaScript만 로드하므로 전체 JS 페이로드가 줄어듭니다.
중요하지 않은 컴포넌트의 JS 로딩이 다른 중요한 컴포넌트의 상호작용을 막지 않습니다.
점진적인 Hydration이 가능하여 TTI를 더욱 개선할 수 있습니다.
➡️

구현 🔗

Astro, Fresh와 같은 최신 프레임워크들이 이 아키텍처를 적극적으로 채택하고 있으며, Next.js의 서버 컴포넌트도 유사한 목표를 가지고 있습니다.
아일랜드 아키텍처. 각 섬마다 독립적인 JS 로딩 및 Hydration 발생
아일랜드 아키텍처. 각 섬마다 독립적인 JS 로딩 및 Hydration 발생

🚀

결론 🔗

오늘은 React 애플리케이션을 사용자에게 보여주는 다양한 렌더링 방식에 대해 깊이 알아보았습니다.
어떤 렌더링 방식이 절대적으로 좋다고 말하기는 어렵습니다. 애플리케이션의 특징, 콘텐츠의 동적성, 성능 요구사항, SEO 중요도 등을 종합적으로 고려하여 가장 적합한 방식을 선택하거나 혼합하여 사용하는 것이 중요합니다.
Next.js와 같은 프레임워크는 이러한 다양한 렌더링 전략을 편리하게 사용하고 조합할 수 있도록 많은 기능을 제공하고 있습니다.
다음 시간에는 React와 함께 사용되는 다양한
자료구조
에 대해 알아보겠습니다.
배열, 연결 리스트, 트리 등 기본 자료구조들이 React의 내부 동작이나 컴포넌트 구현에 어떻게 활용되는지 살펴보며 기본기를 더욱 탄탄히 다져보겠습니다.

참고 🔗