๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API๋Š” ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

hydrate๋Š” React 18์—์„œ hydrateRoot๋กœ ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค. React 18์—์„œ hydrate๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ฑ์ด React 17์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ํ•  ๊ฒƒ์ด๋ผ๋Š” ๊ฒฝ๊ณ ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

React 17 ์ดํ•˜์—์„œ, hydrate๋Š” react-dom/server๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋œ React ์ปดํฌ๋„ŒํŠธ์˜ HTML ์ฝ˜ํ…์ธ ๋ฅผ ๋ธŒ๋ผ์šฐ์ € DOM ๋…ธ๋“œ์— ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

hydrate(reactNode, domNode, callback?)

๋ ˆํผ๋Ÿฐ์Šค

hydrate(reactNode, domNode, callback?)

React 17 ์ดํ•˜์—์„œ hydrate๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด React๊ฐ€ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ HTML์— React๋ฅผ ์—ฐ๊ฒฐ(attach)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { hydrate } from 'react-dom';

hydrate(reactNode, domNode);

React๋Š” domNode์— ์žˆ๋Š” HTML์— ์—ฐ๊ฒฐ๋˜๊ณ , ๊ทธ ๋‚ด๋ถ€์˜ DOM ๊ด€๋ฆฌ๋ฅผ ๋งก์Šต๋‹ˆ๋‹ค. React๋กœ ๋นŒ๋“œ๋œ ์•ฑ์€ ๋ณดํ†ต hydrate๋ฅผ ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋”ฑ ํ•œ ๋ฒˆ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋” ๋‹ค์–‘ํ•œ ์˜ˆ์‹œ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • reactNode: HTML์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” React ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค. React 17์˜ renderToString(<App />)๊ฐ™์€ ReactDOM Server ๋ฉ”์„œ๋“œ๋กœ ๋ Œ๋”๋ง ๋œ <App />์ฒ˜๋Ÿผ, ์ผ๋ฐ˜์ ์œผ๋กœ JSX ์กฐ๊ฐ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

  • domNode: ์„œ๋ฒ„์—์„œ ๋ฃจํŠธ ์š”์†Œ๋กœ ๋ Œ๋”๋ง ๋œ DOM ์š”์†Œ์ž…๋‹ˆ๋‹ค.

  • optional: callback: ์ปดํฌ๋„ŒํŠธ๊ฐ€ hydrate ๋œ ํ›„ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜ ๊ฐ’

hydrate๋Š” null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ ์‚ฌํ•ญ

  • hydrate๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ Œ๋”๋ง ๋œ ์ฝ˜ํ…์ธ ๊ฐ€ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋œ ์ฝ˜ํ…์ธ ์™€ ๋™์ผํ•  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ์ฝ˜ํ…์ธ ์˜ ์ฐจ์ด ์ •๋„๋Š” React๊ฐ€ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜์ง€๋งŒ, ๋ถˆ์ผ์น˜๋Š” ๋ฒ„๊ทธ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ React๋Š” hydration ์ค‘ ์ผ์–ด๋‚œ ๋ถˆ์ผ์น˜์— ๋Œ€ํ•ด ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์ฐจ์ด๊ฐ€ ์กฐ์ •๋œ๋‹ค๋Š” ๋ณด์žฅ์€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ ์ค‘์š”ํ•œ๋ฐ, ๋Œ€๋ถ€๋ถ„์˜ ์•ฑ์—์„œ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋งˆํฌ์—…์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐ ์—„์ฒญ๋‚œ ๋น„์šฉ์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  • ๊ฐ ์•ฑ์—์„œ hydrate๋Š” ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜์„ธ์š”. ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋Œ€์‹  ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์•ฑ์ด ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋œ HTML ์—†์ด ํด๋ผ์ด์–ธํŠธ์—์„œ๋งŒ ๋ Œ๋”๋ง ๋˜๋Š” ๊ฒฝ์šฐ์—” hydrate()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ๋Š” render()(React 17 ์ดํ•˜) ๋˜๋Š” createRoot()(React 18+)๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์‚ฌ์šฉ๋ฒ•

hydrate๋กœ React ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋œ ๋ธŒ๋ผ์šฐ์ € DOM ๋…ธ๋“œ์— ์—ฐ๊ฒฐํ•˜์„ธ์š”.

import { hydrate } from 'react-dom';

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

hydrate()๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋Š” (์„œ๋ฒ„ ์ธก์—์„œ ๋ Œ๋”๋ง ๋˜๋Š” HTML์ด ์—†๋Š”) ์•ฑ์„ ๋งŒ๋“ค ์ˆœ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ๋Š” render()(React 17 ์ดํ•˜) ๋˜๋Š” createRoot()(React 18+)๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋œ HTML Hydrate ํ•˜๊ธฐ

React์—์„œ โ€œhydrationโ€์€ React๊ฐ€ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ HTML์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ hydration์ด ์ผ์–ด๋‚˜๋ฉด React๋Š” ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋œ ๋งˆํฌ์—…์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ณ  ์•ฑ ๋ Œ๋”๋ง์„ ์ด์–ด๋ฐ›์œผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

React๋กœ ๋นŒ๋“œ๋œ ์•ฑ์—์„œ๋Š” ๋ณดํ†ต ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ ๋‹จ ํ•œ ๋ฒˆ ํ•˜๋‚˜์˜ ๋ฃจํŠธ๋งŒ hydate ํ•ฉ๋‹ˆ๋‹ค.

import './styles.css';
import { hydrate } from 'react-dom';
import App from './App.js';

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

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ hydrate๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋” ํ˜ธ์ถœํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. React๋Š” hydrate๊ฐ€ ํ˜ธ์ถœ๋œ ์‹œ์ ๋ถ€ํ„ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ DOM์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. UI๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๋ฉด state๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

hydration์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ hydrateRoot ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.


๋ถˆ๊ฐ€ํ”ผํ•œ hydration ๋ถˆ์ผ์น˜ ์—๋Ÿฌ ๋ฌด์‹œํ•˜๊ธฐ

๋‹จ์ผ ์š”์†Œ์˜ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋‚˜ ํ…์ŠคํŠธ ์ฝ˜ํ…์ธ ๊ฐ€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„ ๋‹ค๋ฅผ ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ฒฝ์šฐ(์˜ˆ: ํƒ€์ž„์Šคํƒฌํ”„), hydration ๋ถˆ์ผ์น˜ ๊ฒฝ๊ณ ๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hydration ๊ฒฝ๊ณ ๋ฅผ ๋ฌด์‹œํ•˜๋ ค๋ฉด suppressHydrationWarning={true}๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

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

์ด ๋ฐฉ๋ฒ•์€ ํ•œ ๋ ˆ๋ฒจ ๊นŠ์ด์—์„œ๋งŒ ์ž‘๋™ํ•˜๋ฉฐ ์ž„์‹œ๋ฐฉํŽธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ์ฝ˜ํ…์ธ ๊ฐ€ ์•„๋‹Œ ์ด์ƒ React๋Š” ์กฐ์ •์„ ์‹œ๋„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ฏ€๋กœ ํ–ฅํ›„ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์„ ๋•Œ๊นŒ์ง€ ์ผ๊ด€์ ์ด์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋‚จ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚จ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.


์„œ๋กœ ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ ๋ฐ ์„œ๋ฒ„ ์ฝ˜ํ…์ธ  ์ฒ˜๋ฆฌํ•˜๊ธฐ

์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์—์„œ ์˜๋„์ ์œผ๋กœ ๋‹ค๋ฅธ ๊ฒƒ์„ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒฝ์šฐ, ํˆฌ ํŒจ์Šค ๋ Œ๋”๋ง(two-pass rendering)์„ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. isClient ๊ฐ™์€ state๋ฅผ ์„ ์–ธํ•ด effect์—์„œ true๋กœ ๋ฐ”๊ฟ” ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

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>
  );
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง ํŒจ์Šค(render pass)์—์„œ ์„œ๋ฒ„์™€ ๊ฐ™์€ ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๋ฏ€๋กœ ๋ถˆ์ผ์น˜๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์œผ๋ฉด์„œ๋„, hydration ์งํ›„ ์ถ”๊ฐ€ ๋ Œ๋”๋ง ํŒจ์Šค๊ฐ€ ๋™๊ธฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‘ ๋ฒˆ ๋ Œ๋”๋ง ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ hydration ์†๋„๊ฐ€ ๋Š๋ ค์ง‘๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋Š” ์ดˆ๊ธฐ HTML ๋ Œ๋”๋ง๋ณด๋‹ค ์ƒ๋‹นํžˆ ๋Šฆ๊ฒŒ ๋กœ๋“œ๋  ์ˆ˜ ์žˆ๊ณ , hydration ์งํ›„์— ๋‹ค๋ฅธ UI๋ฅผ ๋ Œ๋”๋งํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์–ด์ƒ‰ํ•˜๊ฒŒ ๋Š๋‚„ ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐ๋„ท ์†๋„๊ฐ€ ๋Š๋ฆฐ ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜์— ์œ ์˜ํ•˜์„ธ์š”.