Front-End/Next

[NextJS] Hydrate?

Voyage_dev 2022. 10. 12. 23:03

Next.js 프레임워크의 동작원리를 알고있다면 Hydrate에 대해서는 이미 익숙하게 들었을 거다.

 

하지만, 놓치기도 쉬운 개념인 만큼, 이번에 제대로 공부하고 정리 해보려고 한다.

 

일단 React에서 렌더링 되는 과정과 Next에서 렌더링 되는 과정의 차이점에 대해서 정리 해 보자.

React.js

  • HTML과 JS파일을 한꺼번에 보내고 클라이언트에서 JS 코드를 통해 웹 화면을 렌더링한다.

React는 JS파일만을 이용하여 웹 화면을 구성하는 원리를 가지고 있기 때문에 실제 HTML 코드는 안에 내용이 하나도 없는 상태이다. (CSR이 SEO에 적합하지 않은 원리)

// public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

단순 뼈대만 있는 HTML document와 Js 파일들을 클라이언트로 모두 보낸 뒤, 클라이언트 단에서 Js 코드들을 통해 웹 화면을 렌더링 하며 페이지를 그리게 된다.

 

즉, 자바스크립트가 로딩이 안 되면 UI 자체가 안 되기 때문에 카운터를 예로 들면 버튼이나 카운팅 숫자도 안 뜬다(state니까). 그래서 메인 페이지에서 로딩할 데이터 오기 직전 찰나에 헤더랑 푸터 붙어있다가 데이터 로딩되면 그때 메인 컴포넌트가 나타난다.

 

이런 모습을 보기 싫으니까 하이드레이션을 통해 자바스크립트가 로딩이 안 돼도 버튼하고 카운팅 숫자는 뜨게 만든다. 대신 자바스크립트 로딩은 완료가 되지 않았기 때문에 버튼을 눌러도 동작하지는 않는다. 로딩이 완료되면 UI에 덮어 씌운다.

Next.js

  • Pre-rendering된 HTML을 클라이언트에 전송
  • 번들링된 React 코드(Js)들이 클라이언트에 전송
  • 위 두개가 합쳐진게 = Hydrate

Next.js는 클라이언트에게 웹 페이지를 보내기 전에 Server Side 단에서 미리 웹 페이지를 Pre-Rendering 한다. 그리고 Pre-Rendering으로 인해 생성된 HTML document를 클라이언트에게 전송한다.

 

그런데 이 시점에서는 단순히 웹 화면만 보여주는 HTML일 뿐이고, 자바스크립트 요소들이 하나도 없는 상태이다. 웹 화면을 보여주고는 있지만, JS 모듈 뿐만 아니라 단순 이벤트가 DOM요소에 하나도 적용되어 있지 않은 상태이다.

 

그러면 이런 빈 껍데기 같은 웹 페이지를 어떤 방식으로 정상적으로 동작하게 만들까?

 

Next.js Server에서는 Pre-Rendering된 웹 페이지를 클라이언트에게 보내고 나서, 바로 리액트가 번들링 된 자바스크립트 코드들을 클라이언트에게 전송한다.

실제로 Next.js로 제작된 웹페이지를 방문하게 되면 맨 처음 document타입의 파일을 전송받고, 그 후에 렌더링된 React.js 파일들이 다운로드 되는 것을 확인할 수 있다.

 

이러한 리액트 코드들이 이전에 보내진 HTML DOM 요소 위에 한 번 더 렌더링 되는 과정을 Hydrate라고 한다

Hydrate란?

Hydrate는 Server Side 단에서 렌더링 된 정적 페이지와 번들링된 JS파일을 클라이언트에게 보낸 뒤, 클라이언트 단에서 HTML 코드와 React인 JavaScript 코드를 서로 매칭 시키는 과정을 말한다.

이것은 마치 자바스크립트 코드들이 DOM 요소 위에 물을 채우 듯 필요로 하던 요소들을 채운다 하여 Hydrate(수화)라는 용어를 쓴다고 한다.

깜빡임?

Next.js에서 일반적으로 많이 보는 현상이다.

 

새롭게 페이지를 로딩할 때마다 약간 뒤늦게 스타일이 적용되는 듯한 이 과정이, HTML DOM 요소에 뒤늦게 자바스크립트가 동작하고 Hydration 돼서 나타나는 현상이다.

 

그럼 따지고 보면 서버에서 렌더링 한 번, 클라이언트 단에서도 렌더링 한 번, 이러면 비효율적이지 않을까?라는 생각이 들 수 있다.

 

하지만, 서버 단에서 빠르게 Pre-Rendering하고 유저에게 빠른 웹 페이지로 응답할 수 있다는 것이 더욱 큰 이점을 가져간다. 사용자 입장에서 빠른 로딩으로 화면이 보여지기 때문에 두 번 렌더링이 일어난다는 단점을 보완하고도 남는다.

 

단지 각 DOM 요소에 자바스크립트 속성을 매칭하는 목적이지 실제 페이지를 다시 그리는게 아니다.

ReactDOM 함수?

Hydrate는 Next.js에서만 일어나는 과정이 아니고, 사실 ReactDOM의 함수이다.

ReactDOM.render(element, container, [callback]);
ReactDOM.hydrate(element, container, [callback]);
// React 18부터는 hydrate()가 아니라 hydrateRoot() 사용한다

이처럼 render()함수와 같이 hydrate()함수도 ReactDOM에 종속된 함수이다.

 

render()함수가 특정 컴포넌트를 지정된 DOM 요소의 하위로 넣어서 렌더링을 처리한다면, hydrate() 함수는 특정 컴포넌트를 지정된 DOM 요소에 하위로 hydrate 처리를 한다고 알면 된다.

 

즉, hydrate() 함수로 서버에서 받아dhs HTML에 유저가 상호작용할 수 있는 이벤트들을 DOM Tree에 해당하는 DOM 요소를 찾아 부착(연결)하는 일을 말한다.

마무리

Next.js에서 먼저 전달받은 Pre-Rendering된 HTML은 단순하게 HTML으로만 구성된 화면이고, 자바스크립트는 하나도 없는 상태이다. 즉, 웹 화면은 보여주지만, 이벤트들은 적용되기 전 상태이다.

 

그 이후에 번들링 된 React 코드들이 이전에 보내진 HTML DOM 요소 위에 한 번 더 렌더링을 하면서 DOM 요소들을 찾아 자바스크립트 속성을 부착하는 일을 하는 것을 Hydrate라고 한다.

 

출처 : 아래의 사이트들을 보면서 큰 공부 하였습니다

https://nextjs.org/docs/basic-features/pages

https://im-designloper.tistory.com/111

https://narup.tistory.com/230

https://helloinyong.tistory.com/315