본문 바로가기

Next.js

Hydration 이해하기

들어가기

React v18이 릴리즈 된지도 시간이 꽤나 지났고, Next.js 13버전(App Router)에서는 React 18버전을 정식으로 채택하여 RSC를 사용하고 있다.

우리의 PO 프로젝트로 Next.js로 마이그레이션 하기로 결정 되었는데 Next.js에서 중요한 개념 중 하나인 Hydration에 대해 정리하는 시간을 갖고자 한다.

 

Hydration - 수화

한국어로 "수분 공급"이란 뜻을 가지고 있는 이 Hydration이라는 의미는 무엇일까?

 

 

CSR - Client-Side-Rendering

먼저 create-react-app과 같은 React 프로젝트를 생성하면 모든 렌더링이 브라우저에서 발생하게 된다.

이는 빌드된 react 프로젝트의 index.html을 확인해보면 되는데, HTML 문서는 다음과 같다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Maybe some stuff here -->
  </head>
  <body>
    <div id="root"></div>
    <script
      src="/static/bundle.js"
    ></script>
    <script
      src="/static/0.chunk.js"
    ></script>
    <script
      src="/static/main.chunk.js"
    ></script>
  </body>
</html>

 

이렇게 웹페이지를 렌더링하는 과정에서 페이지는 비어져 있고 몇 가지의 번들된 JS 파일을 통해 React가 해당 페이지가 어떤 모습이어야 하는지에 대한 구문을 분석하고

DOM을 삽입하여 페이지의 형태를 그리게 된다.(CSR)

하지만, 여기서 문제가 발생하게 되는데, 위와 같이 번들된 JS를 해석하고 페인팅까지 하는 작업은 소요시간이 오래 걸리고, 그 동안에 사용자는 흰색 화면만을 바라보게 된다.

 

SSR-Server-Side-Rendering

이러한 불편함에 똑똑한 개발자들은 렌더링을 서버에서 수행하게 되면 사용자한테 완전한 형태의 HTML을 보낼 수 있다는 걸 찾아내었다.

그렇게 하면 브라우저가 번들된 JS파일을 다운, 분석, 실행 하는 동안 사용자가 볼 수 있는 내용을 가지게 되는데, 이를 SSR(Server-Side-Rendering)이라고 한다.

 

그런데 여기서 Server Side에서 정적 페이지를 렌더링 하고 렌더링된 HTML파일을 Client로 보내주는데 이 때 HTML 파일은 동적인 컨텐츠가 없는 "메마른" 상태일 것이다.

그래서 이 메마른 상태의 뼈대(HTML)에 수분을 보충해서 생기가 있는 웹페이지를 만드는 기술이 바로 Hydration이라고 한다.

 

Hydration 전 웹사이트
Hydration 후 웹 사이트

 

Hydration 동작원리

여기서 특이한 점이 있는데, 현대의 웹 사이트는 대화형이고 동적인 컨텐츠가 많은 웹사이트가 트렌드이다. 즉, 사용자는 HTML과 CSS만으로는 현대 웹사이트 트렌드를 따라갈 수 없기 때문에

여전히 클라이언트 Javscript를 통해 동적인 컨텐츠를 만드는 작업을 해야한다.

그 작업은 바로, 정적인 페이지를 그렸던 것과 동일한 React코드를 브라우저로 보낸다는 것이다.

정적인 페이지를 만든 것과 동일한 React 코드를 받고 브라우저에서 실행되게 되면 웹 페이지가 어떤 모습이어야 하는지에 대한 페인팅을 하고, 이전에 받은 HTML과 비교하게 된다.

이 과정을 수화라고 하는데, 렌더링과는 차이가 있다.

 

렌더링은 props나 상태가 변경되게 되면 차이점을 조정하고 Virtual DOM에 변경 사항을 업데이트 하여 실제 DOM에 업데이트를 할 준비를 하지만,

Hydration에서는 DOM이 변경되지 않을 것이라고 가정하고 기존 DOM을 채택하는 차이가 있다.

 

실제 코드 예시를 통해 확인해보면 조금 더 이해가 쉬울 수 있는데 React에서 render 함수 hydrate 함수를 비교해보자.

 

ReactDOM.render(element, container, [callback]);

 

ReactDOM.render() 함수는 특정 컴포넌트를 두 번째 파라미터 DOM 요소의 하위로 주입시켜 렌더링을 처리해주고, 렌더링이 완료되면 세 번째 인자의 콜백 함수를 실행하게 된다.

ReactDOM.hydrate(element, container, [callback]);

 

ReactDOM.hydrate() 함수는 특정 컴포넌트를 두 번째 파라미터 DOM 요소에 하위로 hydrate 처리만 한다.

이는 렌더링을 통해 새로운 웹 페이지를 구성할 DOM을 생성하는 것이 아니라, 기존 DOM Tree에서 해당되는 DOM 요소를 찾아 동적인 컨텐츠(이벤트 리스너 등)들만 부착시킨다는 의미인데

여기서 Hydrate는 React 앱이 Hydrate 될 때 DOM 구조가 일치한다고 가정한다는 모습을 잘 보여준다.

 

 

한줄 요약

React에서 Hydration은 SSR을 할 때 Render Tree를 다시 만들지 않고 기존에 있는 DOM에 이벤트만 붙이는 과정을 실행하는 메서드이다.

 

 

 

참고

https://velog.io/@chltjdrhd777/React-hydration%EC%9D%B4%EB%9E%80-root%EB%9E%80

 

[React] hydration이란? (+ root란?)

최근 react 18 관련 자료들과 블로깅을 보면서, 나는 hydration이라는 개념이 아예 리엑트에 내장된... 무언가 랜더링 프로세스중에 한가지가 새로 추가된 것이라고 착각하고 있었다만, 그런게 전혀

velog.io

https://www.joshwcomeau.com/react/the-perils-of-rehydration/