본문 바로가기

FrontEnd

[3분 리액트] React의 Hydration에 대해 알아보자

반응형

원문 : https://blog.saeloun.com/2021/12/16/hydration

 

Understanding Hydration in React applications(SSR)

Ruby on Rails and ReactJS consulting company. We also build mobile applications using React Native

blog.saeloun.com

TLDR

  • 컴포넌트를 렌더링하고 이벤트 핸들러를 연결하는 이 프로세스를 "Hydration(수화)"라고 합니다.
  • 인터랙션 기능 및 이벤트 핸들러를 이용해 '말라있는' HTML에 물을 주는 것과 같습니다.
  • Hydration 후 애플리케이션은 인터랙티브하며 클릭 등 사용자 입력에 응답합니다.

 

수화 사용의 이점

  • SEO 향상
  • 초기 로딩 시간 감소

React 세계에서 우리는 아직 완전히 이해하지 못했을 수 있는
서버 측 렌더링(SSR), 클라이언트 측 렌더링(CSR), ReactDOM, ReactDOMServer 등과 같은 다양한 용어를 접하게 됩니다.

이 용어들을 빨리 이해해 봅시다.

ReactDOM

ReactDOM은 웹 앱의 최상위 수준에서 사용할 수 있는 DOM에 특화된 메서드를 제공하는 패키지입니다.
웹 페이지의 DOM 컴포넌트를 관리하는 효율적인 방법을 제공합니다.

render()

  ReactDOM.render(element, container[, callback])
render() 함수(The render() function)는 ReactDOM의 가장 유용한 함수 중 하나입니다.
React 엘리먼트를 제공된 컨테이너의 DOM에 렌더링한 후 컴포넌트에 대한 참조를 반환합니다
(또는 무상태 컴포넌트-함수 컴포넌트 의 경우 null을 반환).

hydrate()

  ReactDOM.hydrate(element, container[, callback])
hydrate()는 render()와 같지만 HTML 내용이 ReactDOMServer에 의해 렌더링된 컨테이너를 수화하는 데 사용됩니다.
React는 이벤트 리스너를 기존 마크업에 연결하려고 시도합니다.

ReactDOMServer

ReactDOMServer 객체(The ReactDOMServer object)를 사용하면 컴포넌트를 정적 마크업으로 렌더링할 수 있습니다.
renderToString() , renderToStaticMarkup() 두 ReactDOMServer의 함수는 서버와 브라우저 모두에서 사용할 수 있습니다.

Client-side rendering (CSR)

클라이언트 측 렌더링(CSR)은 JavaScript를 사용하여 브라우저에서 직접 페이지를 렌더링하는 것을 의미합니다.

모든 로직, 데이터 가져오기, html 템플릿 생성 및 라우팅은 클라이언트 측에서 처리됩니다.

 

브라우저는 페이지에 대한 요청을 받으면 브라우저에서 실행할 HTML, CSS 및 JS 코드를 보냅니다.

스크립트 태그에는 React 코드의 모든 지침이 포함되어 있습니다. 브라우저에 로드되고 앱이 대화형이 됩니다.

인터넷 속도가 느리거나 번들 크기가 큰 경우 CSR에서 사이트를 사용자에게 표시하는 데 시간이 걸릴 수 있습니다.
사용자는 일반적으로 이러한 시나리오에서 빈 페이지를 봅니다. 그것은 나쁜 사용자 경험을 제공합니다.
웹 크롤러가 빈 사이트의 색인을 생성할 수 없기 때문에 SEO에도 영향을 미칩니다.

이미지는 React Conf 2021 Shaundai의 강연에서 가져왔습니다.

Hydration

React 수화는 렌더링과 유사하게 사용되는 기술이지만
모든 React 컴포넌트를 렌더링하기 위해 빈 DOM을 사용하는 대신
모든 컴포넌트가 HTML로 렌더링된 이미 빌드된 DOM이 있습니다.
기본 React 앱의 모양은 아래와 같습니다.
const root = document.querySelector("#root");
ReactDOM.render(<App name="Saeloun" />, root);
클라이언트 측에서 스크립트를 로드하기 전의 애플리케이션 출력은 다음과 같습니다.
<html>
  <head></head>
  <body>
    <div id="root"></div>
  </body>
</html>

SSR 앱은 아래와 같습니다 : 

// index.js

// hydrate
ReactDOM.hydrate(<App name="Saeloun"/>, document.getElementById('root'));

//server.js

import React from "react";
import ReactDOMServer from "react-dom/server";

app.use("/", (req, res, next) => {
  fs.readFile(path.resolve("./build/index.html"), "utf-8", (err, data) => {
    if (err) {
      console.log(err);
      return res.status(500).send("Some error happened");
    }
    return res.send(ReactDOMServer.renderToString(<App name="Saeloun" />)
    )
  });
});

//App.js

import React from "react";

function App(props) {
  return (
    <div>
      Hello {props.name}!
    </div>
  )
}

export default App;
클라이언트 측에서 스크립트를 로드하기 전의 애플리케이션 출력은 다음과 같습니다.
<html>
  <head></head>
  <body>
    <div id="root">
      <h1>Hello Saeloun!</h1>
    </div>
  </body>
</html>

SSR discussion 에서 논의된 예시를 봅시다.

앱이 준비되면 완전한 대화형 앱을 보여주고 싶습니다.

녹색은 페이지의 인터랙티브한 부분들을 나타냅니다. 즉, 모든 이벤트 핸들러가 연결되어 있습니다(JS가 완전히 로드됨).
CSR에서 JavaScript가 로드되는 동안 사용자에게 표시되는 것은 빈 페이지뿐이므로 사용자 경험이 좋지 않습니다.
SSR에서는 서버의 React 컴포넌트를 HTML로 렌더링하여 사용자에게 보냅니다.
HTML은 대화형이 아닙니다.
그러나 JavaScript가 아직 로드되는 동안 사용자가 무언가를 볼 수 있습니다.

여기서 회색은 볼수는 있으나 아직 완전히 상호 작용하지 않는 부분을 나타냅니다.
JavaScript 코드가 아직 로드되지 않았으므로 버튼을 클릭해도 아무 작업도 수행되지 않습니다.
앱을 인터랙티브하게 만들기 위해 HTML에 이벤트 핸들러를 첨부하도록 React에 지시합니다.
컴포넌트를 렌더링하고 이벤트 핸들러를 연결하는 이 프로세스를 "수화"라고 합니다.
상호 작용 및 이벤트 핸들러로 '마른' HTML에 물을 주는 것과 같습니다.
수화 후 애플리케이션은 대화형이 되어 클릭 등에 응답합니다.
React는 렌더링된 콘텐츠가 서버와 클라이언트 간에 동일할 것으로 예상합니다.
텍스트 내용의 차이를 수정할 수 있습니다.
불일치는 버그로 처리되어야 하며 수정되어야 합니다.
개발 모드에서 React는 수화 중 불일치에 대해 경고합니다.
단일 요소의 속성 또는 텍스트 내용이 서버와 클라이언트 간에 불가피하게 다른 경우(예: 타임스탬프)
요소에 suppressHydrationWarning={true}를 추가하여 경고를 무음으로 만들 수 있습니다.
그러나 과도하게 사용해서는 안됩니다!
초기에 서버와 클라이언트에서 의도적으로 다른 것을 렌더링해야 하는 경우 2단계(twp-pass) 렌더링을 수행할 수 있습니다.
클라이언트에서 다른 것을 렌더링하는 컴포넌트는 componentDidMount()에서 true로 설정할 수 있는
this.state.isClient와 같은 상태 변수를 읽을 수 있습니다.
서버에서와 동일한 콘텐츠를 렌더링하여 불일치를 방지합니다.
그러나 수화 직후에 추가 패스가 동시에 발생합니다.
이 접근 방식은 애플리케이션을 느리게 만들므로 주의해서 사용해야 합니다.
반응형