hydrateRoot
hydrateRoot
๋ react-dom/server
๋ฅผ ํตํด ์ฌ์ ์ ๋ง๋ค์ด์ง HTML๋ก ๊ทธ๋ ค์ง ๋ธ๋ผ์ฐ์ DOM ๋
ธ๋ ๋ด๋ถ์ React ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค.
const root = hydrateRoot(domNode, reactNode, options?)
Reference
hydrateRoot(domNode, reactNode, options?)
์๋ฒ ํ๊ฒฝ์์ React๋ก ์์ ๋ง๋ค์ด์ง HTML์ ํ์ ๋ง๋ค์ด์ง React๋ฅผ hydrateRoot
๋ฅผ ํธ์ถํด โ๋ถ์
๋๋คโ.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);
React๋ domNode
๋ด๋ถ์ HTML์ ๋ถ์ด, ๋ด๋ถ DOM์ ์ง์ ๊ด๋ฆฌํ ๊ฒ์
๋๋ค. App์ React๋ก ์ ๋ถ ๋ง๋ค์๋ค๋ฉด ๋ณดํต์ ๋จ ํ๋์ root component์ ํจ๊ป hydrateRoot
๋ฅผ ํ ๋ฒ ํธ์ถํ ๊ฒ์
๋๋ค.
์๋ ์ฌ๋ฌ ์์๋ฅผ ํ์ธํด๋ณด์ธ์.
Parameters
-
domNode
: ์๋ฒ์์ root element๋ก ๋ ๋๋ง๋ DOM element -
reactNode
: ์์ ์กด์ฌํ๋ HTML์ ๋ ๋๋งํ๊ธฐ ์ํ โReact ๋ ธ๋โ ์ ๋๋ค. ์ฃผ๋กReactDOM Server
์renderToPipeableStream(<App />)
์ ๊ฐ์ ๋ฉ์๋๋ก ๋ ๋๋ง๋<App />
๊ฐ์ JSX ์กฐ๊ฐ๋ค์ ๋๋ค. -
optional
options
: React root์ ์ต์ ์ ์ฃผ๊ธฐ ์ํ ๊ฐ์ฒด์ ๋๋ค.- optional
onRecoverableError
: React๊ฐ ์๋ฌ์์ ์๋์ผ๋ก ํ๋ณต๋์์ ๋ ํธ์ถํ๋ ์ฝ๋ฐฑํจ์. - optional
identifierPrefix
: React๊ฐ ID๋ก ์ฌ์ฉํ๋ ์ ๋์ฌ๋กuseId
๋ก ๋ง๋ค์ด์ง ๊ฐ์ ๋๋ค. ๊ฐ์ ํ์ด์ง์์ ์ฌ๋ฌ root๋ฅผ ์ฌ์ฉํ ๋ ์ถฉ๋์ ํผํ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฒ์์ ์ฌ์ฉํ ๊ฐ๊ณผ ๋ฐ๋์ ๋์ผํ ๊ฐ์ด์ด์ผ ํฉ๋๋ค.
- optional
Returns
hydrateRoot
๋ 2๊ฐ์ง ๋ฉ์๋๊ฐ ํฌํจ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค : render
๊ทธ๋ฆฌ๊ณ unmount
.
Caveats
hydrateRoot()
๋ ์๋ฒ์์ ๋ ๋๋ง๋ ๋ด์ฉ๊ณผ ํ์ ๋ ๋๋ง๋ ๋ด์ฉ์ด ๋์ผํ ๊ฒ์ ๊ธฐ๋ํฉ๋๋ค. ๋ฐ๋ผ์ ๋์ผํ์ง ์์ ๋ถ๋ถ๋ค์ ์ง์ ๋ฒ๊ทธ๋ก ์ทจ๊ธํด์ฃผ๊ฑฐ๋ ๊ณ ์ณ์ค์ผ ํฉ๋๋ค.- ๊ฐ๋ฐ ๋ชจ๋์์ , React๊ฐ hydration ์ค์ ๋์ผํ์ง ์์ ๋ถ๋ถ์ ๋ํด ๊ฒฝ๊ณ ํด์ค๋๋ค. ์์ฑ์ด ๋์ผํ์ง ์์ ๊ฒฝ์ฐ์ ํด๋น ์์ฑ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋ ๊ฒ์ด๋ผ๊ณ ๋ณด์ฅํ ์ ์์ต๋๋ค. ๋ชจ๋ markup์ ๋ณด์ฅํ์ง ์๋ ๊ฒ์ ์ฑ๋ฅ๋ฉด์์ ์ค์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. markup์ด ๋์ผํ์ง ์๋ ๊ฒฝ์ฐ๋ ๋๋ฌผ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ markup์ ๊ฒ์ฆํ๋ ๋น์ฉ์ ๊ต์ฅํ ๋น์๋๋ค.
- ์ฌ๋ฌ๋ถ์ App์์
hydrateRoot
๋ฅผ ๋จ ํ ๋ฒ๋ง ํธ์ถํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ๋ง์ฝ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ํ๋ ์์ํฌ๊ฐ ๋์ ํธ์ถํด ์ค ๊ฒ์ ๋๋ค. - App์ ์ฌ์ ์ ๋ ๋๋ง๋ HTML ์์ด ํด๋ผ์ด์ธํธ์์ ์ง์ ๋ ๋๋ง์ ํ๋ค๋ฉด
hydrateRoot()
์ ์ง์๋์ง ์์ต๋๋ค.createRoot()
๋ฅผ ๋์ ์ฌ์ฉํด์ฃผ์ธ์.
root.render(reactNode)
hydrate๋ React root๋ถํฐ ๋ด๋ถ ์ปดํฌ๋ํธ๋ฅผ ์๋ก์ด React ์ปดํฌ๋ํธ๋ก ๊ฐฑ์ ํ๊ธฐ ์ํด root.render
๋ฅผ ํธ์ถํด์ฃผ์ธ์. ๋ธ๋ผ์ฐ์ DOM ์์๋ค๋ ํจ๊ป ๊ฐฑ์ ๋ฉ๋๋ค.
root.render(<App />);
React๋ hydrate๋ root
๋ถํฐ ๋ด๋ถ๋ฅผ <App />
์ผ๋ก ๊ฐฑ์ ํฉ๋๋ค.
์๋ ์์๋ฅผ ํ์ธํด๋ณด์ธ์.
Parameters
reactNode
: ๊ฐฑ์ ํ๊ณ ์ถ์ โReact ๋ ธ๋โ์ ๋๋ค. ์ฃผ๋ก<App />
๊ฐ์ JSX๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธฐ์ง๋ง,createElement()
๋ก ๋ง๋ React ์๋ฆฌ๋จผํธ๋ฅผ ๋๊ฒจ๋ ๋๊ณ ๋ฌธ์์ด์ด๋ ์ซ์,null
, ํน์undefined
๋ฅผ ๋๊ฒจ๋ ๋ฉ๋๋ค.
Returns
root.render
๋ undefined
๋ฅผ ๋ฐํํฉ๋๋ค.
Caveats
- hydrate๊ฐ ๋๋๊ธฐ ์ ์
root.render
๋ฅผ ํธ์ถํ๋ฉด React๋ ์๋ฒ์์ ๋ ๋๋ง๋ HTML์ ๋ชจ๋ ์์ ๊ณ ํด๋ผ์ด์ธํธ์์ ๋ ๋๋ง๋ ์ปดํฌ๋ํธ๋ค๋ก ์์ ํ ๊ต์ฒดํฉ๋๋ค.
root.unmount()
root.unmount
๋ฅผ ํธ์ถํด React root๋ถํฐ ๊ทธ ํ์์ ๋ ๋๋ง๋ ํธ๋ฆฌ๋ฅผ ์ญ์ ํฉ๋๋ค.
root.unmount();
์ฒ์๋ถํฐ ๋๊น์ง React๋ก ๋ง๋ ์ฑ์ root.unmount
๋ฅผ ํธ์ถํ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ์์ต๋๋ค.
์ฃผ๋ก React root๋ถํฐ ํน์ ๊ทธ ์์์์๋ถํฐ ์์๋ DOM node๋ค์ ๋ค๋ฅธ ์ฝ๋์ ์ํด DOM์์ ์ญ์ ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, jQuery ํญ ํจ๋์ด ํ์ฑํ ๋์ด ์์ง ์์ ํญ์ DOM์์ ์ง์ด๋ค๊ณ ๊ฐ์ ํด๋ด
์๋ค. ํญ์ด ์ง์์ง๋ฉด, React root์ ๊ทธ ๋ด๋ถ๋ฅผ ํฌํจํด ๊ทธ ์์ ๋ชจ๋ ๊ฒ์ด ์ง์์ง๊ฒ ๋๊ณ DOM์์ ๋ํ ์ง์์ง๊ฒ ๋ฉ๋๋ค. root.unmount
๋ฅผ ํธ์ถํด React์๊ฒ ์ญ์ ๋ ์ปจํ
์ธ ๋ค์ โ๊ทธ๋งโ ๋ค๋ฃจ๋ผ๊ณ ์๋ ค์ฃผ์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ญ์ ๋์ด๋ฒ๋ฆฐ React root ๋ด๋ถ์ ์ปดํฌ๋ํธ๋ค์ ์ญ์ ๋์ง ์์ ๊ฒ์ด๋ฉฐ, โ๊ตฌ๋
โ์ฒ๋ผ ์ปดํจํ
์์์ ์์ ๋กญ๊ฒ ๋์์ฃผ์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค.
root.unmount
๋ฅผ ํธ์ถํ๋ฉด root ๋ด๋ถ์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ unmountํ๊ณ root DOM node์์ React๋ฅผ โ๋ผ์ดโ๋
๋๋ค. root ๋ด๋ถ์ event handler์ state๊น์ง ๋ชจ๋ ํฌํจํด unmount ๋ฐ ์ญ์ ๋ฉ๋๋ค.
Parameters
root.unmount
๋ ๊ทธ ์ด๋ค ํ๋ผ๋ฏธํฐ๋ ๋ฐ์ง ์์ต๋๋ค.
Returns
root.unmount
returns undefined
.
Caveats
-
root.unmount
๋ฅผ ํธ์ถํ๋ฉด root๋ถํฐ ๊ทธ ์์ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ unmount๋๊ณ root DOM node์์ React๋ฅผ ๋ผ์ด๋ ๋๋ค. -
root.unmount
๋ฅผ ํ๋ฒ ํธ์ถํ ์ดํ์root.render
๋ฅผ root์ ๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค. unmount๋ root์ ๋ค์root.render
๋ฅผ ํธ์ถํ๋ ค๊ณ ํ๋ค๋ฉด โCannot update an unmounted rootโ ์๋ฌ๋ฅผ throwํ๊ฒ ๋ฉ๋๋ค.
์ฌ์ฉ ์์
์๋ฒ์์ ๋ ๋๋ง๋ HTML์ hydrateํ๊ธฐ
react-dom/server
๋ก ์ฑ์ HTML์ ์์ฑํ๋ค๋ฉด, ํด๋ผ์ด์ธํธ์์ hydrateํด์ฃผ์ด์ผ ํฉ๋๋ค.
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
์ ์ฝ๋๋ฅผ ํตํด ์๋ฒ HTML์ ๋ธ๋ผ์ฐ์ DOM node์์ React ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด hydrate ํด์ค ๊ฒ ์ ๋๋ค. ์ฃผ๋ก ์ฑ์ ์์ํ ๋ ๋จ ํ ๋ฒ ์คํํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉ์ค์ด๋ผ๋ฉด ํ๋ ์์ํฌ๊ฐ ์์์ ์คํํด ์ค ๊ฒ์ ๋๋ค.
์ฑ์ hydrateํ๊ธฐ ์ํด์ React๋ ์ปดํฌ๋ํธ์ ๋ก์ง์ ์ฌ์ ์ ์๋ฒ์์ ๋ง๋ค์ด ์ง HTML์ โ๋ถ์ผโ๊ฒ ์ ๋๋ค. Hydration์ ํตํด ์๋ฒ์์ ๋ง๋ค์ด์ง ์ต์ด์ HTML ์ค๋ ์ท์ ๋ธ๋ผ์ฐ์ ์์ ์์ ํ ์ธํฐ๋ํฐ๋ธํ ์ฑ์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ฒ ๋ฉ๋๋ค.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
hydrateRoot
๋ฅผ ๋ค์ ํธ์ถํ๊ฑฐ๋ ๋ค๋ฅธ ๊ณณ์์ ๋ ํธ์ถํ ํ์๋ ์์ต๋๋ค. ์ด ์์ ๋ถํฐ React๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์ DOM์ ๋ค๋ฃจ๊ฒ ๋ฉ๋๋ค. ๋์ UI๋ฅผ ๊ฐฑ์ ํ๊ธฐ ์ํด์ state๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
document ์ ์ฒด๋ฅผ hydrateํ๊ธฐ
React๋ก ์ฑ์ ๋ชจ๋ ๋ง๋ค์์ ๊ฒฝ์ฐ <html>
ํ๊ทธ๋ฅผ ํฌํจํด JSX๋ก ๋ ์ ์ฒด document๋ฅผ ๋ ๋๋งํ ์ ์์ต๋๋ค.
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>
);
}
์ ์ฒด document๋ฅผ hydrateํ๊ธฐ ์ํด์ ๊ธ๋ก๋ฒ ๋ณ์์ธ document
๋ฅผ hydrateRoot
์ ์ฒซ๋ฒ์งธ ์ธ์๋ก ๋๊น๋๋ค:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);
์ด์ฉ ์ ์๋ hydration ๋ถ์ผ์น ์๋ฌ ์ต์ ํ๊ธฐ
์ด๋ค element์ ์์ฑ์ด๋ text content๊ฐ ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ์ด์ฉ ์ ์์ด ๋ค๋ฅผ ๋(์๋ฅผ ๋ค์ด, timestamp๋ฅผ ์ด์ฉํ๋ค๊ฑฐ๋), hydration ๋ถ์ผ์น ๊ฒฝ๊ณ ๋ฅผ ์๋ณด์ด๊ฒ ํ ์ ์์ต๋๋ค.
ํด๋น element์์ hydration ๊ฒฝ๊ณ ๋ฅผ ๋๊ธฐ ์ํด์ suppressHydrationWarning={true}
๋ฅผ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
export default function App() { return ( <h1 suppressHydrationWarning={true}> Current Date: {new Date().toLocaleDateString()} </h1> ); }
์ด๊ฒ์ ํ ๋จ๊ณ ์๋๊น์ง๋ง ์ ์ฉ๋๋ฉฐ ๋น์ ํ์ถ๊ตฌ๋ฅผ ์๋ํ ๊ฒ์ ๋๋ค. ๋จ์ฉํ์ง ๋ง์ธ์. text context๊ฐ ์๋ ํ, React๋ ์๋ชป๋ ๋ถ๋ถ์ ์์ ํ์ง ์์ ๊ฒ์ด๋ฉฐ ๊ฐฑ์ ์ด ์ผ์ด๋๊ธฐ ์ ๊น์ง๋ ๋ถ์ผ์นํ ์ํ๋ก ๋จ์์์ ๊ฒ์ ๋๋ค.
์๋ก ๋ค๋ฅธ ํด๋ผ์ด์ธํธ์ ์๋ฒ ์ปจํ ์ธ ๋ค๋ฃจ๊ธฐ
์๋์ ์ผ๋ก ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ์๋ก ๋ค๋ฅธ ๋ด์ฉ์ ๋ ๋๋งํ๊ธธ ์ํ๋ค๋ฉด, ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ์๋ก ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ๋ ๋๋งํ๋ฉด ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ์์ ์๋ฒ์๋ ๋ค๋ฅธ ๊ฒ์ ๋ ๋๋งํ ๋ ํด๋ผ์ด์ธํธ์์ Effect์์ true
๋ก ํ ๋น๋๋ isClient
๊ฐ์ ์ํ ๋ณ์๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
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> ); }
์ด ๋ฐฉ๋ฒ์ ์ฒ์์ ์๋ฒ์ ๋์ผํ ๊ฒฐ๊ณผ๋ฌผ์ ๋ ๋๋งํ๊ฒ ๋์ด ๋ถ์ผ์น ๋ฌธ์ ๋ฅผ ํผํ๊ฒ ๋๊ณ , hydrationํ์ ์๋ก์ด ๊ฒฐ๊ณผ๋ฌผ์ด ๋๊ธฐ์ ์ผ๋ก ๋ ๋๋ง๋ฉ๋๋ค.
hydrate๋ root ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ
root์ hydrating์ด ๋๋ ์ดํ์, root.render
๋ฅผ ํธ์ถํด React ์ปดํฌ๋ํธ์ root๋ฅผ ์
๋ฐ์ดํธ ํ ์ ์์ต๋๋ค. createRoot
์๋ ๋ค๋ฅด๊ฒ HTML๋ก ์ต์ด์ ์ปจํ
์ธ ๊ฐ ์ด๋ฏธ ๋ ๋๋ง ๋์ด ์๊ธฐ ๋๋ฌธ์ ์์ฃผ ์ฌ์ฉํ ํ์๋ ์์ต๋๋ค.
hydration ํ ์ด๋ค ์์ ์ root.render
๋ฅผ ํธ์ถํ๋ค๋ฉด, ๊ทธ๋ฆฌ๊ณ ์ปดํฌ๋ํธ์ ํธ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์ด์ ์ ๋ ๋๋งํ๋ ๊ตฌ์กฐ์ ์ผ์นํ๋ค๋ฉด, React๋ ์ํ๋ฅผ ๊ทธ๋๋ก ๋ณด์กดํฉ๋๋ค. input์ ์ด๋ป๊ฒ ํ์ดํํ๋์ง์ ๋ฐ๋ผ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. ์ฆ, ์๋ ์์์์์ฒ๋ผ ๋งค์ด ๋ง๋ค ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ๋ฐ๋ณต์ ์ธ render
๋ ๋ฌธ์ ์์ด ๋ ๋๋ง ๋๋ค๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค:
import { hydrateRoot } from 'react-dom/client'; import './styles.css'; 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);
hydrate๋ root์ root.render
๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํํ ์ผ์ ์๋๋๋ค. ๋ด๋ถ ์ปดํฌ๋ํธ ์ค ํ ๊ณณ์์ ์ํ ์
๋ฐ์ดํธ๋ฅผ ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์
๋๋ค.