๐ข hydration์ ๋ํด์
์๋ฒ๊ฐ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ ๋ณด๋ด์ค HTML์ ๋ธ๋ผ์ฐ์ ๊ฐ javascript ๊ธฐ๋ฅ์ ๋ค์ ๋ถ์ฌ์
์ธํฐ๋์
๊ฐ๋ฅํ ์ํ๊ฐ ๋๋ ๊ฒ
๊ณผ์ :
1. ์๋ฒ๊ฐ html์ ๋ ๋๋งํด์ ๋ณด๋
2. js๊ฐ ๋ค ์๋ ๋ ์ฌ์ฉ์๋ ์ผ๋จ ํ๋ฉด์ ๋นจ๋ฆฌ ๋ณด๋๊ฒ ๊ฐ๋ฅ
3. js๊ฐ ๋ก๋๋จ
4. ๊ธฐ์กด html์ ๋ณด๊ณ ์ฐ๊ฒฐ ์์
์ ํจ
5. ํด๋ฆญ, ์
๋ ฅ, ์ํ ๋ณ๊ฒฝ๋ฑ์ด ์ ์ ์๋ํจ
-> ์ฒ์ ํ๋ฉด์ ๋น ๋ฅด๊ฒ ๋ณด์ฌ์ฃผ๊ณ , ๋์ค์ ๋์์ ๋ถ์ด๋ ๋ฐฉ์!
๋ง์ฝ์ CSR๋ง ์ด๋ค๋ฉด,
์ฒ์์ ๋น div๋ง ๋ฐ๊ณ js ๋ค ๋ฐ์์ผ ํ๋ฉด์ด ๋ฐ ์ ์์.
๊ทผ๋ฐ SSR + hydration์ด๋ฉด? ์ผ๋จ ๋น ๋ฅด๊ฒ ํ๋ฉด ํ์ธ์ ํ ์ ์๋๊ฑฐ์
https://react.dev/reference/react-dom/client/hydrateRoot
hydrateRoot๋ก ๋ฆฌ์กํธ์์ ์ด๋ป๊ฒ html์ ๋ฆฌ์กํธ ๋ถ์ด๋์ง ์ค๋ช
ํด์ค..
์ฒ์์ ์ดํด๊ฐ ์ข ์ด๋ ค์ ์
์์ )
//index.js
import './styles.css';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(
document.getElementById('root'),
<App />
);
//index.html
<!--
HTML content inside <div id="root">...</div>
was generated from App by react-dom/server.
-->
<div id="root"><h1>Hello, world!</h1><button>You clicked me <!-- -->0<!-- --> times</button></div>
//App.js
import { useState } from 'react';
export default function App() {
return (
<>
<h1>Hello, world!</h1>
<Counter />
</>
);
}
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
You clicked me {count} times
</button>
);
}
์ด๊ฑธ๋ณด๋ฉด ์์์๋๊ฑด
๋ณดํต CSR์ด๋ผ๋ฉด ์ฒจ์ root์์ ๋น๊ป๋ฐ๊ธฐ๊ฐ ๋ค์ด์๊ฒ ์ง๋ง hydrateRoot๋ฅผ ์ด๋ค๋ฉด ์ด๋ฏธ Hello, world! ์ด์ฉ๊ณ ๊ฐ ์๋ html์ด ๋ค์ด์์๋๊ฑฐ์
๋ด๊ฐ ์ฒ์์ hydration๊ฐ๋ ์ ๋ค์์ ๋๋ ์ ์ฒจ์ ์๋ฒ์์ ๋ณด๋ด์ค html์์ id๋ class๋ฅผ ๊ฐ์ ธ์จ๋ค ์ปดํฌ๋ํธ๋ ์ฐ๊ฒฐํ๋ ์์ด๊ฒ ๊ตฌ๋... ์ด๋ ๊ฒ ์์ํ๋๋ฐ ๊ทธ๊ฒ ์๋์์
๊ทธ๋ฅ CSR๊ณผ ๋น์ทํ๊ฒ ์ฝ๋์์ฑํ๊ณ hydrateRoot๋ง ํ๋ฉด, ๊ฑฐ๊ธฐ์ ๋ง์ถฐ์ ๋จผ์ html๋ก ๋ด๋ ค์ฃผ๊ณ js๊ฐ ๋ก๋๋๊ณ ๋์ ๊ทธ DOM ๊ตฌ์กฐ, ํ ์คํธ, ์กฐ๊ฑด๋ถ ๋ ๋๋ง ๋ฑ์ ๋น๊ตํ๋ฉด์ ์ฐ๊ฒฐ๋๋ ๊ฑฐ์.
๊ทธ๋ฐ๋ฐ, ์๋ฒ์์ ๋ด๋ ค์ค html๊ณผ ํด๋ผ์ด์ธํธ์ ์ฒซ๋ ๋ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅผ ๋ ์ด๊ธ๋จ์ด ๋ฐ์ํ ์ ์์ ์ด๊ฑธ hydration mismatch๋ผ๊ณ ํ๋ค๊ณ ํจ
๐ hydration mismatch๋ ?
์๋ฒ๊ฐ ๋ง๋ html์ด๋ js๊ฐ ์ฒ์ ๋ ๋๋งํ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅผ ๋ ์๊น.
ํ ์คํธ๊ฐ ์กฐ๊ธ ๋ค๋ฅด๊ฑฐ๋, ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ณด๋ ๊ตฌ์กฐ๊ฐ ํฌ๊ฒ ๋ค๋ฅผ ๋ hydration ๊ณผ์ ์์ ์ด๊ธ๋๋ ์ํ๋ฅผ ๋งํจ
์ด ๊ฒฝ์ฐ ๊ฒฝ๊ณ ๊ฐ ๋จ๊ฑฐ๋, ๊นจ์ง๊ฑฐ๋, ์๋ฒ์์ ๋ด๋ ค์ค html์ ๋ฒ๋ฆฌ๊ณ ํด๋ผ์ด์ธํธ ๋ ๋๋ง์ผ๋ก ์ ํ๋ ์์์
์๋ฅผ๋ค์ด ํ์ ์ข ๋ฅ์ ๋ฐ๋ผ UI๋ฅผ ๋ค๋ฅด๊ฒ ๋ณด์ฌ์ค์ผํ๋ค๊ณ ํ์
๊ณฐ ํ์์ธ ๊ฒฝ์ฐ BearPage๋ฅผ ๋ณด์ฌ์ค์ผํ๊ณ
๊ณฐํ์์ด ์๋ ๊ฒฝ์ฐ AllPage๋ฅผ ๋ณด์ฌ์ค์ผํจ
function Page() {
const isBear = localStorage.getItem('isBear') === 'true';
return isBear ? <BearPage /> : <AllPage />;
}
์ด๊ฑธ ์ํด ์ด๋ ๊ฒ ์์ฑํด๋๋ค๋ฉด?
์๋ฒ๋ ๋ก์ปฌ์คํ ๋ฆฌ์ง์์ ๊ฐ์ ๋ชป์ฝ์ด์ AllPage ๋ ๋ํ ์๋ ์์
๊ทผ๋ฐ ์ฌ์ค ๊ณฐ์ด์๋๋ผ๋ฉด..?
์๋ฒ html๊ณผ ํด๋ผ์ด์ธํธ์์์ ๋ ๋๊ฒฐ๊ณผ์ ๋ถ์ผ์น๋ก ๊ณ ์ฅ๋ ์์์
์ด๋ฅผ ์ํด์ ์๋ฒ์์๋ isBear๊ฐ์ ์ ํํ ์์์๊ฒํ๊ฑฐ๋ ์์ ๊ณตํต ํ์ด์ง๋ฅผ ๋ง๋ค์ด์ fallback UI๋ก ์ฐ๊ฑฐ๋ ์ด๋ฐ ์ ๋ต์ ํผ์น ์ ์์๊ฑฐ์
์๋ฌดํผ UX์ ์ ๋ง ์ข์ ๋ฐฉ๋ฒ๊ฐ์
์ธํฐ๋ท์ด ๋๋ฆฐํ๊ฒฝ์์๋ ์ด์ฐ๋๋ ๋ญ๊ฐ ๋ณด์ธ๋ค๋๊ฑด ๋๋ฌด์ข์๊ฑฐ๊ณ ..
์ธ์ ๊ฐ ํด๋ด์ผ์ง
๋