React 18 useDeferredValue ์‹ฌํ™”: ๊ฒ€์ƒ‰ ์ž๋™์™„์„ฑ์—์„œ ๋””๋ฐ”์šด์‹ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ์ด์œ 

React 18 useDeferredValue ์‹ฌํ™”: ๊ฒ€์ƒ‰ ์ž๋™์™„์„ฑ์—์„œ ๋””๋ฐ”์šด์‹ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ์ด์œ 

๐Ÿ’ง React Query: SSR Hydration ์ „๋žต ๋ฝ€๊ฐœ๊ธฐ

์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ, ์–ด๋–ป๊ฒŒ ํด๋ผ์ด์–ธํŠธ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ์“ธ๊นŒ์š”?

"์ƒˆ๋กœ๊ณ ์นจํ•  ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๊ฐ€ ๊นœ๋นก๊ฑฐ๋ฆฌ๋‚˜์š”?"
Next.js ๊ฐ™์€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR) ํ™˜๊ฒฝ์„ ์“ฐ๋Š”๋ฐ๋„, ํ™”๋ฉด์ด ๋œฐ ๋•Œ '๋กœ๋”ฉ ์ค‘...'์ด ๋ณด์ธ๋‹ค๋ฉด ๋ญ”๊ฐ€ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์„œ๋ฒ„์—์„œ ํž˜๋“ค๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™”๋Š”๋ฐ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ทธ๊ฑธ ๋ชจ๋ฅด๊ณ  ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๋ ค ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .
์ด ๋น„ํšจ์œจ์„ ํ•ด๊ฒฐํ•˜๋Š” ํ•ต์‹ฌ ์—ด์‡ , ๋ฐ”๋กœ Hydration(์ˆ˜๋ถ„ ๊ณต๊ธ‰)์— ๋Œ€ํ•ด ์•„์ฃผ ์‰ฝ๊ฒŒ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋งŽ์€ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค์ด React Query๋ฅผ SSR๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” ๋ฌธ์ œ๋กœ ๊ณจ๋จธ๋ฆฌ๋ฅผ ์•“์Šต๋‹ˆ๋‹ค.
์˜ค๋Š˜ ์ด ๊ธ€์„ ํ†ตํ•ด ์„œ๋ฒ„์˜ ์ƒํƒœ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— '๋ฌผ ํ๋ฅด๋“ฏ' ์ „๋‹ฌํ•˜๋Š” ์ „๋žต์„ ๋งˆ์Šคํ„ฐํ•ด ๋ด…์‹œ๋‹ค.


๐Ÿค” 1. Dehydration & Hydration์ด ๋ญ”๊ฐ€์š”?

์šฉ์–ด๊ฐ€ ๋„ˆ๋ฌด ์–ด๋ ต์ฃ ? ์‰ฌ์šด ๋น„์œ ๋กœ ์ดํ•ดํ•ด ๋ด…์‹œ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ์บ ํ•‘์„ ๊ฐ„๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿœ ์ปต๋ผ๋ฉด ๋น„์œ  (The Cup Noodle Analogy)

  • 1. ์„œ๋ฒ„ (๊ณต์žฅ):
    ๋ง›์žˆ๋Š” ๋ผ๋ฉด(๋ฐ์ดํ„ฐ)์„ ๋“์—ฌ์„œ ์ˆ˜๋ถ„์„ ์ซ™ ๋บ๋‹ˆ๋‹ค. ์ด๋ฅผ Dehydration(๊ฑด์กฐ/์ˆ˜๋ถ„ ์ œ๊ฑฐ)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
    ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ€๋ณ๊ฒŒ ํฌ์žฅํ•ด์„œ ๋ธŒ๋ผ์šฐ์ €๋กœ ๋ฐฐ์†กํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.
  • 2. ์ด๋™ (HTML ์ „์†ก):
    ๊ฑด์กฐ๋œ ๋ผ๋ฉด(์ง๋ ฌํ™”๋œ JSON ๋ฐ์ดํ„ฐ)์ด HTML์— ๋‹ด๊ฒจ ๋ธŒ๋ผ์šฐ์ €๋กœ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค.
  • 3. ํด๋ผ์ด์–ธํŠธ (๋ธŒ๋ผ์šฐ์ €):
    ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฐ›์ž๋งˆ์ž ๋œจ๊ฑฐ์šด ๋ฌผ์„ ๋ถ€์–ด ๋จน์„ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    ์ด๊ฒƒ์ด ๋ฐ”๋กœ Hydration(์ˆ˜๋ถ„ ๊ณต๊ธ‰)์ž…๋‹ˆ๋‹ค.

์ฆ‰, ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ "์–ผ๋ ค๋‘์—ˆ๋‹ค๊ฐ€" ํด๋ผ์ด์–ธํŠธ์—์„œ "๋…น์—ฌ์„œ" ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.


⚔️ 2. ๋‘ ๊ฐ€์ง€ ํ•ต์‹ฌ ์ „๋žต: initialData vs Hydration

React Query์—์„œ SSR์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์ƒํ™ฉ์— ๋งž์ถฐ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์ „๋žต A: `initialData` ์‚ฌ์šฉํ•˜๊ธฐ

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์ปดํฌ๋„ŒํŠธ์˜ props๋กœ ๋„˜๊ฒจ์ฃผ๊ณ , ๊ทธ๊ฑธ useQuery์˜ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๋„ฃ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๐Ÿ‘ ์žฅ์ : ๊ตฌํ˜„์ด ๋งค์šฐ ์ง๊ด€์ ์ด๊ณ  ์‰ฝ์Šต๋‹ˆ๋‹ค.
๐Ÿ‘Ž ๋‹จ์ : ์ปดํฌ๋„ŒํŠธ ๊นŠ์ด๊ฐ€ ๊นŠ์–ด์ง€๋ฉด ๋ฐ์ดํ„ฐ ์ „๋‹ฌ(Prop Drilling)์ด ํž˜๋“ญ๋‹ˆ๋‹ค.

์ „๋žต B: Hydration API ์‚ฌ์šฉํ•˜๊ธฐ (๊ถŒ์žฅ)

Next.js์˜ dehydrate์™€ HydrationBoundary๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ‘œ์ค€ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
React Query๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•ด ์ฃผ๋ฏ€๋กœ Props๋ฅผ ๊ณ„์† ๋„˜๊ฒจ์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ตฌ๋ถ„ initialData ๋ฐฉ์‹ Hydration ๋ฐฉ์‹ (์ถ”์ฒœ)
๋ณต์žก๋„ ๋‚ฎ์Œ (์‰ฌ์›€) ์ค‘๊ฐ„ (์„ค์ • ํ•„์š”)
๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ์ „์—ญ ๊ด€๋ฆฌ (Cache)
์‚ฌ์šฉ์ฒ˜ ๋‹จ์ˆœํ•œ ํŽ˜์ด์ง€ ๋ณต์žกํ•œ ์•ฑ / ๊นŠ์€ ๊ตฌ์กฐ

๐Ÿ’ป 3. Hydration ํŒจํ„ด ์‹ค์ „ ๊ตฌํ˜„ (Next.js 14 App Router ๊ธฐ์ค€)

์ตœ์‹  Next.js ํ™˜๊ฒฝ์—์„œ ๊ฐ€์žฅ ๊ถŒ์žฅ๋˜๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(Server Component)์—์„œ์˜ ๊ตฌํ˜„ ํ๋ฆ„์„ ๋ณด์—ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

// app/posts/page.tsx (์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ)

import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';

export default async function PostsPage() {
  // 1. ์„œ๋ฒ„ ์ „์šฉ QueryClient ์ƒ์„ฑ
  const queryClient = new QueryClient();

  // 2. ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (prefetch)
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
  });

  return (
    // 3. ๋ฐ์ดํ„ฐ๋ฅผ ์ง๋ ฌํ™”(Dehydrate)ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ
    <HydrationBoundary state={dehydrate(queryClient)}>
      <PostsList />
    </HydrationBoundary>
  );
}

⚠️ ์ฃผ์˜์‚ฌํ•ญ: makeQueryClient

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ์šด QueryClient๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์‹ฑ๊ธ€ํ†ค(์ „์—ญ ๋ณ€์ˆ˜)์œผ๋กœ ๋งŒ๋“ค๋ฉด ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์„ž์ด๋Š” ๋”์ฐํ•œ ์‚ฌ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!


๐ŸŽ“ ๋งˆ์น˜๋ฉฐ

Hydration์€ ์ฒ˜์Œ์—” ๋ณต์žกํ•ด ๋ณด์ด์ง€๋งŒ, ํ•œ ๋ฒˆ ์„ธํŒ…ํ•ด ๋‘๋ฉด SEO ์ ์ˆ˜์™€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX) ๋‘ ๋งˆ๋ฆฌ ํ† ๋ผ๋ฅผ ๋ชจ๋‘ ์žก์„ ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋ฌด๊ธฐ์ž…๋‹ˆ๋‹ค.
์ด์ œ '๋กœ๋”ฉ ์ค‘' ์—†๋Š” ์พŒ์ ํ•œ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๊นŒ์ง€ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐฐ์†ก๋˜๊ธธ ์‘์›ํ•ฉ๋‹ˆ๋‹ค!

๋Œ“๊ธ€ ์“ฐ๊ธฐ