번역 자료 / / 2025. 5. 28. 06:44

[react 번역] hydrateRoot API

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


hydrateRoot

hydrateRoot는 서버에서 미리 생성된 HTML이 있는 브라우저 DOM 노드에 React 컴포넌트를 표시할 수 있게 해줍니다.

const root = hydrateRoot(domNode, reactNode, options?)
  • 레퍼런스
    • hydrateRoot(domNode, reactNode, options?)
    • root.render(reactNode)
    • root.unmount()
  • 사용법
    • 서버 렌더링된 HTML 하이드레이션하기
    • 전체 문서 하이드레이션하기
    • 불가피한 하이드레이션 불일치 에러 무시하기
    • 클라이언트와 서버 내용이 다를 때 처리
    • 하이드레이션된 루트 컴포넌트 업데이트하기
    • 프로덕션 환경에서 에러 로깅하기
  • 문제 해결
    • root.render에 두 번째 인자를 전달했을 때의 에러

레퍼런스

hydrateRoot(domNode, reactNode, options?)

서버에서 미리 렌더링된 HTML이 있는 DOM 요소에 React를 "연결"하려면 hydrateRoot를 호출하세요.

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

const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, <App />);

React는 해당 domNode 내부의 기존 HTML에 "붙어서" 그 이후의 DOM 관리를 takeover합니다. 대부분의 앱에서는 루트 컴포넌트에 대해 한 번만 호출합니다.

파라미터

  • domNode: 서버에서 렌더링된 루트 DOM 요소
  • reactNode: 기존 HTML을 렌더링할 때 사용한 React 노드(JSX 등)
  • options(선택): 객체. 루트에 대한 옵션입니다.
    • onCaughtError: Error Boundary에서 에러를 잡았을 때 호출되는 콜백
    • onUncaughtError: Error Boundary에서 잡히지 않은 에러가 발생했을 때 호출되는 콜백
    • onRecoverableError: React가 자동으로 복구 가능한 에러를 처리할 때 호출되는 콜백
    • identifierPrefix: 여러 루트에서 useId로 생성되는 ID의 접두사(서버와 동일해야 함)

반환값

hydrateRootrenderunmount 메서드를 가진 객체를 반환합니다.

주의사항

  • hydrateRoot()는 서버에서 렌더링된 내용과 클라이언트에서 렌더링된 내용이 동일해야 합니다. 불일치는 버그로 간주하고 반드시 수정해야 합니다.
  • 개발 모드에서는 불일치에 대해 경고가 표시됩니다. 성능상 이유로 모든 마크업을 검증하지는 않습니다.
  • 대부분의 앱에서는 한 번만 호출합니다. 프레임워크를 사용한다면 프레임워크가 대신 호출할 수 있습니다.
  • 클라이언트에서만 렌더링되는 앱에는 hydrateRoot()를 사용하지 마세요. 이 경우 createRoot()를 사용하세요.

root.render(reactNode)

하이드레이션된 루트의 React 컴포넌트를 업데이트하려면 root.render를 호출하세요.

root.render(<App />);

파라미터

  • reactNode: 업데이트할 React 노드(JSX 등)

반환값

root.render는 아무것도 반환하지 않습니다.

주의사항

  • 하이드레이션이 끝나기 전에 root.render를 호출하면 기존 서버 렌더링된 HTML이 모두 지워지고 클라이언트 렌더링으로 전환됩니다.

root.unmount()

root.unmount를 호출하면 해당 루트의 React 트리를 DOM에서 제거하고, 관련 리소스를 정리합니다.

root.unmount();

반환값

root.unmount는 아무것도 반환하지 않습니다.

주의사항

  • 호출 시 트리 전체가 언마운트되고 React가 해당 DOM 노드에서 완전히 분리됩니다.
  • 한 번 언마운트하면 다시 root.render를 호출할 수 없습니다. 호출 시 "Cannot update an unmounted root" 에러가 발생합니다.

사용법

서버 렌더링된 HTML 하이드레이션하기

앱의 HTML이 서버에서 생성된 경우, 클라이언트에서 반드시 하이드레이션해야 합니다.

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

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

이렇게 하면 서버에서 생성된 HTML에 React의 로직이 "붙어서" 완전히 인터랙티브한 앱이 됩니다.

주의사항

  • hydrateRoot에 전달하는 React 트리는 서버에서 렌더링한 결과와 동일한 출력을 내야 합니다. 불일치가 있으면 사용자 경험이 깨질 수 있습니다.

전체 문서 하이드레이션하기

React로 전체 문서를 JSX로 렌더링할 수도 있습니다.

function App() {
  return (
    <html>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="/styles.css"></link>
        <title>My app</title>
      </head>
      <body>
        <Router />
      </body>
    </html>
  );
}

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

hydrateRoot(document, <App />);

불가피한 하이드레이션 불일치 에러 무시하기

서버와 클라이언트에서 어쩔 수 없이 다른 값(예: 타임스탬프 등)이 렌더링되는 경우, 해당 요소에 suppressHydrationWarning={true}를 추가해 경고를 무시할 수 있습니다.

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

이 속성은 한 단계만 적용되며, 꼭 필요한 경우에만 사용하세요. React는 불일치한 텍스트 내용을 패치하지 않습니다.

클라이언트와 서버 내용이 다를 때 처리

의도적으로 서버와 클라이언트에서 다른 내용을 렌더링해야 한다면, Effect에서 상태를 변경해 두 번 렌더링하는 방식을 사용할 수 있습니다.

import { useState, useEffect } from "react";

export default function App() {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

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

이 방식은 하이드레이션 속도를 늦출 수 있으니 사용자 경험에 주의하세요.

하이드레이션된 루트 컴포넌트 업데이트하기

하이드레이션이 끝난 후에는 root.render로 루트 컴포넌트를 업데이트할 수 있습니다. 하지만 일반적으로는 컴포넌트 내부에서 상태를 업데이트하는 방식이 더 흔합니다.

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

const root = hydrateRoot(
  document.getElementById('root'),
  <App counter={0} />
);

let i = 0;
setInterval(() => {
  root.render(<App counter={i} />);
  i++;
}, 1000);

프로덕션 환경에서 에러 로깅하기

옵션으로 에러 핸들러를 지정해 에러 로깅 시스템을 구현할 수 있습니다.

import { hydrateRoot } from "react-dom/client";
import App from "./App.js";
import { reportCaughtError } from "./reportError";

const container = document.getElementById("root");
hydrateRoot(container, <App />, {
  onCaughtError: (error, errorInfo) => {
    if (error.message !== "Known error") {
      reportCaughtError({
        error,
        componentStack: errorInfo.componentStack,
      });
    }
  },
});

문제 해결

root.render에 두 번째 인자를 전달했을 때의 에러

root.render는 한 개의 인자만 받습니다. 옵션은 hydrateRoot에 전달해야 합니다.

// 🚩 잘못된 예시
root.render(App, {onUncaughtError});

// ✅ 올바른 예시
const root = hydrateRoot(container, <App />, {onUncaughtError});

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

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유