hydrateRoot
hydrateRoot
๋ react-dom/server
๋ฅผ ํตํด ์ฌ์ ์ ๋ง๋ค์ด์ง HTML๋ก ๊ทธ๋ ค์ง ๋ธ๋ผ์ฐ์ DOM ๋
ธ๋ ๋ด๋ถ์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค.
const root = hydrateRoot(domNode, reactNode, options?)
Reference
hydrateRoot(domNode, reactNode, options?)
์๋ฒ ํ๊ฒฝ์์ ๋ฆฌ์กํธ๋ก ์์ ๋ง๋ค์ด์ง HTML์ ํ์ ๋ง๋ค์ด์ง ๋ฆฌ์กํธ๋ฅผ hydrateRoot
๋ฅผ ํธ์ถํด โ๋ถ์
๋๋คโ.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);
๋ฆฌ์กํธ๋ domNode
๋ด๋ถ์ HTML์ ๋ถ์ด, ๋ด๋ถ DOM์ ์ง์ ๊ด๋ฆฌํ ๊ฒ์
๋๋ค. App์ React๋ก ์ ๋ถ ๋ง๋ค์๋ค๋ฉด ๋ณดํต์ ๋จ ํ๋์ root component์ ํจ๊ป hydrateRoot
๋ฅผ ํ ๋ฒ ํธ์ถํ ๊ฒ์
๋๋ค.
์๋ ์ฌ๋ฌ ์์๋ฅผ ํ์ธํด๋ณด์ธ์.
Parameters
-
domNode
: ์๋ฒ์์ root element๋ก ๋ ๋๋ง๋ DOM element -
reactNode
: ์์ ์กด์ฌํ๋ HTML์ ๋ ๋๋งํ๊ธฐ ์ํ โ๋ฆฌ์กํธ ๋ ธ๋โ ์ ๋๋ค. ์ฃผ๋กReactDOM Server
์renderToPipeableStream(<App />)
์ ๊ฐ์ ๋ฉ์๋๋ก ๋ ๋๋ง๋<App />
๊ฐ์ JSX ์กฐ๊ฐ๋ค์ ๋๋ค. -
optional
options
: ๋ฆฌ์กํธ root์ ์ต์ ์ ์ฃผ๊ธฐ ์ํ ๊ฐ์ฒด์ ๋๋ค.- optional
onRecoverableError
: ๋ฆฌ์กํธ๊ฐ ์๋ฌ์์ ์๋์ผ๋ก ํ๋ณต๋์์ ๋ ํธ์ถํ๋ ์ฝ๋ฐฑํจ์. - optional
identifierPrefix
: ๋ฆฌ์กํธ๊ฐ ID๋ก ์ฌ์ฉํ๋ ์ ๋์ฌ๋กuseId
๋ก ๋ง๋ค์ด์ง ๊ฐ์ ๋๋ค. ๊ฐ์ ํ์ด์ง์์ ์ฌ๋ฌ root๋ฅผ ์ฌ์ฉํ ๋ ์ถฉ๋์ ํผํ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฒ์์ ์ฌ์ฉํ ๊ฐ๊ณผ ๋ฐ๋์ ๋์ผํ ๊ฐ์ด์ด์ผ ํฉ๋๋ค.
- optional
Returns
hydrateRoot
๋ 2๊ฐ์ง ๋ฉ์๋๊ฐ ํฌํจ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค : render
๊ทธ๋ฆฌ๊ณ unmount
.
Caveats
hydrateRoot()
๋ ์๋ฒ์์ ๋ ๋๋ง๋ ๋ด์ฉ๊ณผ ํ์ ๋ ๋๋ง๋ ๋ด์ฉ์ด ๋์ผํ ๊ฒ์ ๊ธฐ๋ํฉ๋๋ค. ๋ฐ๋ผ์ ๋์ผํ์ง ์์ ๋ถ๋ถ๋ค์ ์ง์ ๋ฒ๊ทธ๋ก ์ทจ๊ธํด์ฃผ๊ฑฐ๋ ๊ณ ์ณ์ค์ผ ํฉ๋๋ค.- ๊ฐ๋ฐ ๋ชจ๋์์ , ๋ฆฌ์กํธ๊ฐ hydration ์ค์ ๋์ผํ์ง ์์ ๋ถ๋ถ์ ๋ํด ๊ฒฝ๊ณ ํด์ค๋๋ค. ์์ฑ์ด ๋์ผํ์ง ์์ ๊ฒฝ์ฐ์ ํด๋น ์์ฑ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋ ๊ฒ์ด๋ผ๊ณ ๋ณด์ฅํ ์ ์์ต๋๋ค. ๋ชจ๋ markup์ ๋ณด์ฅํ์ง ์๋ ๊ฒ์ ์ฑ๋ฅ๋ฉด์์ ์ค์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. markup์ด ๋์ผํ์ง ์๋ ๊ฒฝ์ฐ๋ ๋๋ฌผ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ markup์ ๊ฒ์ฆํ๋ ๋น์ฉ์ ๊ต์ฅํ ๋น์๋๋ค.
- ์ฌ๋ฌ๋ถ์ App์์
hydrateRoot
๋ฅผ ๋จ ํ ๋ฒ๋ง ํธ์ถํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ๋ง์ฝ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ํ๋ ์์ํฌ๊ฐ ๋์ ํธ์ถํด ์ค ๊ฒ์ ๋๋ค. - App์ ์ฌ์ ์ ๋ ๋๋ง๋ HTML ์์ด ํด๋ผ์ด์ธํธ์์ ์ง์ ๋ ๋๋ง์ ํ๋ค๋ฉด
hydrateRoot()
์ ์ง์๋์ง ์์ต๋๋ค.createRoot()
๋ฅผ ๋์ ์ฌ์ฉํด์ฃผ์ธ์.
root.render(reactNode)
hydrate๋ ๋ฆฌ์กํธ root๋ถํฐ ๋ด๋ถ ์ปดํฌ๋ํธ๋ฅผ ์๋ก์ด ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ก ๊ฐฑ์ ํ๊ธฐ ์ํด root.render
๋ฅผ ํธ์ถํด์ฃผ์ธ์. ๋ธ๋ผ์ฐ์ DOM ์์๋ค๋ ํจ๊ป ๊ฐฑ์ ๋ฉ๋๋ค.
root.render(<App />);
๋ฆฌ์กํธ๋ hydrate๋ root
๋ถํฐ ๋ด๋ถ๋ฅผ <App />
์ผ๋ก ๊ฐฑ์ ํฉ๋๋ค.
์๋ ์์๋ฅผ ํ์ธํด๋ณด์ธ์.
Parameters
reactNode
: ๊ฐฑ์ ํ๊ณ ์ถ์ โ๋ฆฌ์กํธ ๋ ธ๋โ์ ๋๋ค. ์ฃผ๋ก<App />
๊ฐ์ JSX๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธฐ์ง๋ง,createElement()
๋ก ๋ง๋ ๋ฆฌ์กํธ ์๋ฆฌ๋จผํธ๋ฅผ ๋๊ฒจ๋ ๋๊ณ ๋ฌธ์์ด์ด๋ ์ซ์,null
, ํน์undefined
๋ฅผ ๋๊ฒจ๋ ๋ฉ๋๋ค.
Returns
root.render
๋ undefined
๋ฅผ ๋ฐํํฉ๋๋ค.
Caveats
- hydrate๊ฐ ๋๋๊ธฐ ์ ์
root.render
๋ฅผ ํธ์ถํ๋ฉด ๋ฆฌ์กํธ๋ ์๋ฒ์์ ๋ ๋๋ง๋ HTML์ ๋ชจ๋ ์์ ๊ณ ํด๋ผ์ด์ธํธ์์ ๋ ๋๋ง๋ ์ปดํฌ๋ํธ๋ค๋ก ์์ ํ ๊ต์ฒดํฉ๋๋ค.
root.unmount()
root.unmount
๋ฅผ ํธ์ถํด ๋ฆฌ์กํธ root๋ถํฐ ๊ทธ ํ์์ ๋ ๋๋ง๋ ํธ๋ฆฌ๋ฅผ ์ญ์ ํฉ๋๋ค.
root.unmount();
์ฒ์๋ถํฐ ๋๊น์ง ๋ฆฌ์กํธ๋ก ๋ง๋ ์ฑ์ root.unmount
๋ฅผ ํธ์ถํ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ์์ต๋๋ค.
์ฃผ๋ก ๋ฆฌ์กํธ root๋ถํฐ ํน์ ๊ทธ ์์์์๋ถํฐ ์์๋ DOM node๋ค์ ๋ค๋ฅธ ์ฝ๋์ ์ํด DOM์์ ์ญ์ ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, jQuery ํญ ํจ๋์ด ํ์ฑํ ๋์ด ์์ง ์์ ํญ์ DOM์์ ์ง์ด๋ค๊ณ ๊ฐ์ ํด๋ด
์๋ค. ํญ์ด ์ง์์ง๋ฉด, ๋ฆฌ์กํธ root์ ๊ทธ ๋ด๋ถ๋ฅผ ํฌํจํด ๊ทธ ์์ ๋ชจ๋ ๊ฒ์ด ์ง์์ง๊ฒ ๋๊ณ DOM์์ ๋ํ ์ง์์ง๊ฒ ๋ฉ๋๋ค. root.unmount
๋ฅผ ํธ์ถํด ๋ฆฌ์กํธ์๊ฒ ์ญ์ ๋ ์ปจํ
์ธ ๋ค์ โ๊ทธ๋งโ ๋ค๋ฃจ๋ผ๊ณ ์๋ ค์ฃผ์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ญ์ ๋์ด๋ฒ๋ฆฐ ๋ฆฌ์กํธ root ๋ด๋ถ์ ์ปดํฌ๋ํธ๋ค์ ์ญ์ ๋์ง ์์ ๊ฒ์ด๋ฉฐ, โ๊ตฌ๋
โ์ฒ๋ผ ์ปดํจํ
์์์ ์์ ๋กญ๊ฒ ๋์์ฃผ์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค.
root.unmount
๋ฅผ ํธ์ถํ๋ฉด root ๋ด๋ถ์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ unmountํ๊ณ root DOM node์์ ๋ฆฌ์กํธ๋ฅผ โ๋ผ์ดโ๋
๋๋ค. root ๋ด๋ถ์ event handler์ state๊น์ง ๋ชจ๋ ํฌํจํด unmount ๋ฐ ์ญ์ ๋ฉ๋๋ค.
Parameters
root.unmount
๋ ๊ทธ ์ด๋ค ํ๋ผ๋ฏธํฐ๋ ๋ฐ์ง ์์ต๋๋ค.
Returns
render
๋ null
์ ๋ฆฌํดํฉ๋๋ค.
Caveats
-
root.unmount
๋ฅผ ํธ์ถํ๋ฉด root๋ถํฐ ๊ทธ ์์ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ unmount๋๊ณ root DOM node์์ ๋ฆฌ์กํธ๋ฅผ ๋ผ์ด๋ ๋๋ค. -
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์์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด hydrate ํด์ค ๊ฒ ์ ๋๋ค. ์ฃผ๋ก ์ฑ์ ์์ํ ๋ ๋จ ํ ๋ฒ ์คํํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉ์ค์ด๋ผ๋ฉด ํ๋ ์์ํฌ๊ฐ ์์์ ์คํํด ์ค ๊ฒ์ ๋๋ค.
์ฑ์ hydrateํ๊ธฐ ์ํด์ ๋ฆฌ์กํธ๋ ์ปดํฌ๋ํธ์ ๋ก์ง์ ์ฌ์ ์ ์๋ฒ์์ ๋ง๋ค์ด ์ง HTML์ โ๋ถ์ผโ๊ฒ ์ ๋๋ค. Hydration์ ํตํด ์๋ฒ์์ ๋ง๋ค์ด์ง ์ต์ด์ HTML ์ค๋ ์ท์ ๋ธ๋ผ์ฐ์ ์์ ์์ ํ ์ธํฐ๋ํฐ๋ธํ ์ฑ์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ฒ ๋ฉ๋๋ค.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
hydrateRoot
๋ฅผ ๋ค์ ํธ์ถํ๊ฑฐ๋ ๋ค๋ฅธ ๊ณณ์์ ๋ ํธ์ถํ ํ์๋ ์์ต๋๋ค. ์ด ์์ ๋ถํฐ ๋ฆฌ์กํธ๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์ DOM์ ๋ค๋ฃจ๊ฒ ๋ฉ๋๋ค. UI๋ฅผ ๊ฐฑ์ ํ๊ธฐ ์ํด์ use state๋ฅผ ๋์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
document ์ ์ฒด๋ฅผ hydrateํ๊ธฐ
๋ฆฌ์กํธ๋ก ์ฑ์ ๋ชจ๋ ๋ง๋ค์์ ๊ฒฝ์ฐ <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๊ฐ ์๋ ํ, ๋ฆฌ์กํธ๋ ์๋ชป๋ ๋ถ๋ถ์ ์์ ํ์ง ์์ ๊ฒ์ด๋ฉฐ ๊ฐฑ์ ์ด ์ผ์ด๋๊ธฐ ์ ๊น์ง๋ ๋ถ์ผ์นํ ์ํ๋ก ๋จ์์์ ๊ฒ์ ๋๋ค.
์๋ก ๋ค๋ฅธ ํด๋ผ์ด์ธํธ์ ์๋ฒ ์ปจํ ์ธ ๋ค๋ฃจ๊ธฐ
์๋์ ์ผ๋ก ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ์๋ก ๋ค๋ฅธ ๋ด์ฉ์ ๋ ๋๋งํ๊ธธ ์ํ๋ค๋ฉด, ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ์๋ก ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ๋ ๋๋งํ๋ฉด ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ์์ ์๋ฒ์๋ ๋ค๋ฅธ ๊ฒ์ ๋ ๋๋งํ ๋ ํด๋ผ์ด์ธํธ์์ 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
๋ฅผ ํธ์ถํด ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ root๋ฅผ ์
๋ฐ์ดํธ ํ ์ ์์ต๋๋ค. createRoot
์๋ ๋ค๋ฅด๊ฒ HTML๋ก ์ต์ด์ ์ปจํ
์ธ ๊ฐ ์ด๋ฏธ ๋ ๋๋ง ๋์ด ์๊ธฐ ๋๋ฌธ์ ์์ฃผ ์ฌ์ฉํ ํ์๋ ์์ต๋๋ค.
hydration ํ ์ด๋ค ์์ ์ root.render
๋ฅผ ํธ์ถํ๋ค๋ฉด, ๊ทธ๋ฆฌ๊ณ ์ปดํฌ๋ํธ์ ํธ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์ด์ ์ ๋ ๋๋งํ๋ ๊ตฌ์กฐ์ ์ผ์นํ๋ค๋ฉด, ๋ฆฌ์กํธ๋ ์ํ๋ฅผ ๊ทธ๋๋ก ๋ณด์กดํฉ๋๋ค. 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
๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํํ ์ผ์ ์๋๋๋ค. ๋ด๋ถ ์ปดํฌ๋ํธ ์ค ํ ๊ณณ์์ ์ํ ์
๋ฐ์ดํธ๋ฅผ ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์
๋๋ค.