--- id: wiki-2026-0508-hydration title: Hydration category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Client Hydration, SSR Hydration] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [web, ssr, react, frontend] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: react --- # Hydration ## 매 한 줄 > **"매 server 가 render 한 static HTML 에 client JS 가 event handler / state 를 부여하는 과정"**. 매 SSR 의 SEO + first paint 이점 + SPA 의 interactivity 의 결합. 2026 시점 매 trend 는 매 less hydration — Astro Islands, React Server Components, Qwik resumability 가 매 full-page hydration 을 대체. ## 매 핵심 ### 매 단계 1. **Server**: render to HTML string (`renderToString` / `renderToPipeableStream`). 2. **Client**: HTML parsing → first paint (TTFB / FCP). 3. **Hydration**: JS download → React/framework 가 component tree 의 event listener attach + state restore. 4. **Interactive**: TTI 도달. ### 매 cost - 매 download + parse + execute JS — 매 모바일 mid-tier 에서 무거움. - Hydration mismatch — 매 server vs client output 차이 시 warning + re-render. - 매 unused interactivity 도 매 hydrate (Wasted hydration). ### 매 modern alternatives - **Selective / progressive hydration** (React 18+): Suspense 단위로 lazy hydrate. - **Islands architecture** (Astro, Fresh): 매 interactive island 만 ship + hydrate. - **Resumability** (Qwik): hydration 자체 제거 — 매 server 에서 serialize 한 closure 를 매 event 시점에 lazy resume. - **React Server Components**: 매 server-only component 는 ship X — 매 client component 만 hydrate. ### 매 응용 1. Next.js / Remix App Router (RSC + selective hydration). 2. Astro (islands). 3. Qwik / QwikCity (resumability). 4. SvelteKit, SolidStart (fine-grained reactivity, hydration cheaper). ## 💻 패턴 ### React 19 SSR + hydrateRoot ```ts // server.ts import { renderToPipeableStream } from "react-dom/server"; import App from "./App"; const stream = renderToPipeableStream(, { bootstrapScripts: ["/client.js"], onShellReady() { stream.pipe(res); }, }); // client.ts import { hydrateRoot } from "react-dom/client"; import App from "./App"; hydrateRoot(document, ); ``` ### Suspense for selective hydration ```tsx }> {/* 매 이 boundary 만 lazy hydrate */} ``` ### Astro Islands ```astro --- import Counter from "../components/Counter.svelte"; ---

Static

{/* 매 viewport 진입 시 hydrate */} ``` ### Qwik resumability ```tsx import { component$, useSignal } from "@builder.io/qwik"; export default component$(() => { const c = useSignal(0); // 매 click 전에는 JS 미실행 — 매 lazy resume return ; }); ``` ### Avoiding hydration mismatch ```tsx // 매 client-only value (Date.now, window) 는 useEffect 에서 function Now() { const [t, setT] = useState(null); useEffect(() => setT(new Date().toISOString()), []); return {t ?? ""}; // 매 server: empty, client: 실제값 } ``` ### React Server Components (Next.js) ```tsx // app/page.tsx — server component, 매 hydrate X export default async function Page() { const data = await db.posts.findMany(); return ; // 매 ClientWidget 만 hydrate } ``` ### Streaming SSR (Node) ```ts const stream = renderToPipeableStream(, { onShellReady() { res.setHeader("content-type", "text/html"); stream.pipe(res); }, onError(err) { console.error(err); }, }); ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Mostly static + 적은 island | Astro / 11ty + islands | | Full app, dynamic data | Next.js App Router (RSC) | | Extreme TTI 우선 | Qwik (resumability) | | Fine-grained reactivity | Svelte / Solid | | 매 SEO 불필요 SPA | CSR (no hydration) | **기본값**: Next.js 15 App Router (RSC + selective hydration). 매 mostly-static 사이트 는 Astro. ## 🔗 Graph - 부모: [[SSR]] · [[Web Architecture]] - 변형: [[Selective Hydration]] · [[Islands Architecture]] · [[Resumability]] - 응용: [[Next.js]] · [[Astro]] · [[Qwik]] · [[Remix]] - Adjacent: [[Fiber_Architecture|Fiber Architecture]] · [[Streaming SSR]] · [[React Server Components]] · [[Core Web Vitals Optimization (INP, LCP 개선)|Core Web Vitals]] ## 🤖 LLM 활용 **언제**: TTI / LCP / INP 진단, framework 선택, hydration mismatch 디버깅. **언제 X**: 매 SEO + first paint 둘 다 불필요한 internal tool — 매 CSR SPA 면 충분. ## ❌ 안티패턴 - **Hydration mismatch (Date.now, Math.random)**: 매 server-client output 불일치 → re-render. - **Hydrating entire static page**: 매 island 분리 안 함 → JS 무겁게. - **Heavy useEffect in root**: 매 hydration 직후 main thread block. - **Conditional render based on `typeof window`**: 매 mismatch 의 흔한 원인. - **Hydrating below-the-fold immediately**: 매 selective + visibility 활용. ## 🧪 검증 / 중복 - Verified (React 19 docs, Next.js 15 docs, Astro docs, Qwik docs, Addy Osmani *Hydration* 2024). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — hydration + islands + RSC + resumability 정리 |