Don’t worry about failures

Hydrate에 대해 본문

React

Hydrate에 대해

허흥 2024. 3. 22. 07:39
728x90

정의

React 애플리케이션에서 SSR을 통해 HTML을 가져와서 React컴포넌트로 변환하고, 클라이언트 측에서 상호작용이 가능한 앱으로 만드는 과정을 말한다.

조금 더 풀어서 생각해보면, SSR은 서버에서 HTML을 생성해서 client에게 전달한다. 이 HTML은 JS가 없는 건조(dry)한 상태이다. 이러한 건조한 상태에서 Hydrate(수화)의 단어 의미 대로 JS를 통해 각 이벤트들을 연결해줌으로써 촉촉한 상태를 만들어 준다는 의미이다.

 

그럼 만약에 React 애플리케이션에서 SSR을 통해 렌더링을 진행하고자 했지만 Hydrate를 하지 않으면 어떻게 될까?

서버에서 만든 HTML을 무시하고 리액트가 새롭게 만든다. 즉, 서버측에서 생성된 HTML이 아닌 Javascript를 통해 UI를 생성하는 CSR과 같이 동작한다는 것이다. 

 

사용법

import { hydrateRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);

 

*참고

18 이전에는 다음과 같이 사용됐으나 18버전부터 deprecated되어 위와 같이사용

import { hydrate } from 'react-dom';

hydrate(<App />, document.getElementById('root'));

 

 

보통 SSR의 경우 Next.js와 같은 프레임워크를 사용한다. Next.js는 기본적으로 hydrate를 적용하며, 별도로 끄는 설정은 존재하지 않는다. 

 

Hydration 주의점

hydration mismatch

hydration을 하는 도중 mismatch의 error가 발생할 수 있다. 발생할 수 있는 상황에 대해 봐보자.

 

가장 큰 개념은 서버에서 제공된 HTML과 React에 의해 만들어진 렌더링 결과물이 일치해야하지만 그렇지 않은 경우 hydration mismatch가 발생하게 된다.

 

예제는 공식 홈페이지 및 참고페이지에서 발췌했다.

1. SSR 페이지에 WebAPI를 사용하는 경우

SSR의 경우 환경이 브라우저가 아니기 때문에 WebAPI는 존재하지 않는다. 이 때문에 실제 리액트에서 만든 결과물이랑 서버에서 내려온 HTML과 다른 결과값을 보여줄 수다.

예시를 봐보자.

export default function App() {
  const isClient = typeof window !== 'undefined';

  return (
    <h1>
      {isClient ? 'Is Client' : 'Is Server'}
    </h1>
  );
}

 

이를 해결하고자 하려면 useState와 같은 상태값을 활용할 수 있다. 

const [isClient, setIsClient] = useState(false);

이와 같이 상태값을 서버렌더링이 끝난 후에 js가 실행된 이후로 상태를 변경하여 UI에 반영하도록 하면 mismatch가 일어나지 않는다.

하지만 이는 렌더링이 두번 일어나는 것이기 때문에 비효율적일 수 있다.

 

이를 위해 dynamic import와 ssr: false를 통해 적용할 수 있다.

// no-ssr.jsx
const NoSSR = () => {
  return <h1>Is Client</h1>
}

// index.js
const NoSSR = dynamic(() => import('../no-ssr'), { ssr: false });

export default function App() {

  return (
    <div>
      <NoSSR />
    </div>
  );
}

 

 

2. 서버에서 페이지를 만든 시점이랑 클라이언트에서 만든 시점이랑 페이지가 다를 경우

export default function App() {
  return (
    <h1>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

예제와 같이 시간을 명시하게 된다고하면 만든 시점이 다르기 때문에 Hydration mismatch가 일어나게 될 것이다. 

이러한 문제를 해결하기 위해서는 suppressHydrationWarning={true} 옵션이 존재한다.

export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

하지만 이는 단순 경고 안나게해주는 정도 수준의 해결이다.

 

이 이외에도 다양한 mismatch가 존재한다.

3. browser extension을 통한 html변경에 의한 mismatch

4. ValidateDOMNesting에 의한 mismatch => 해당 부분을 별도 글로 남길 예정

5. safari에서 전화번호 형식(xx-xxx-xxx)등과 같은 text가 존재하면 자동으로 전화번호로써 여기고 링크를 거는 등의 행위에 의한 mismatch

 

이와 같은 mismatch들이 존재한다.

 

참고:

https://react.dev/reference/react-dom/client/hydrateRoot

https://blog.hwahae.co.kr/all/tech/13604

 

React의 hydration mismatch 알아보기 – 화해 블로그 | 기술 블로그

React의 hydration mismatch 알아보기 화해는 에러 트래킹 서비스인 Sentry를 사용하고 있는데요. 지난해 Next.js의 static export로 배포한 이벤트 페이지에서 hydration mismatch 에러가 쌓이기 시작했습니다.

blog-wp.hwahae.co.kr

 

728x90

'React' 카테고리의 다른 글

MSW에 대해  (0) 2024.03.26
전역 상태관리에 대해  (0) 2024.03.25
React StrictMode에 대해  (0) 2024.03.21
useTransition에 대해  (0) 2024.03.16
concurrent mode에 대해  (0) 2024.03.15