๐ 10. Next.js SSR/SSG ํ๊ฒฝ์ ์ด๊ธฐ ๋ฐ์ดํฐ ์ฃผ์ (Hydration)
๐ ๊ฐ์
์๋ฒ๊ฐ ๋ฏธ๋ฆฌ ๊ตฌ์์ค ๋ฐ์ดํฐ ์บ์๋ฅผ ํด๋ผ์ด์ธํธ ์บ์๋ก ์ด๋ป๊ฒ ์์ ํ๊ฒ ๋๊ฒจ์ฃผ์ด(Hydration), ํด๋ผ์ด์ธํธ์ ๋ถํ์ํ ์คํผ๋๋ฅผ ์๋ฒฝ ์ญ์ ํ๋์ง ๋ฐฐ์๋๋ค.
๐ ๋ชฉ์ฐจ
- โ๏ธ ์์ฒ ์ด์ ๊ณ ๋ฏผ: "๋ถ๋ช ํ Next.js๊ฐ ์งฑ ๋น ๋ฅด๋ค ํ๋๋ฐ..."
- ๐ค ์ ์์์ผ ํ๋๊ฐ: ์บ์ ์ฌ๊ฐ์ง๋ (Cache Blind Spot)
- 1. ์ ์ A:
initialData(๊ฐ์ฅ ์ฝ๊ณ ์ง๊ด์ ์ธ Prop ์ ๋ฌ) - 2. ์ ์ B: `` (์ง์ ํ ์ํคํ ์ฒ์ ๊ฝ)
- ๐ ๋ฐฐ์ด ๋ด์ฉ ์ ๊ฒํ๊ธฐ (Quiz)
"์์ฒ ๋, ์๋ฒ ๋ ๋๋ง(SSR) ๋ค ํด๋๊ณ ์ ๋ธ๋ผ์ฐ์ ์ผ์ง์๋ง์ ๋ฐ์ดํฐ๋ฅผ ๋ Fetch ํ๋ ค๊ณ ๋น๋น์ ๋๋์? ์ํ(Hydration)๊ฐ ๋๊ฒผ์์์!"
โ๏ธ ์์ฒ ์ด์ ๊ณ ๋ฏผ: "๋ถ๋ช ํ Next.js๊ฐ ์งฑ ๋น ๋ฅด๋ค ํ๋๋ฐ..."
(๊ธ์์ผ ์์นจ, ํฌ๋กฌ ํผํฌ๋จผ์ค ํญ์ ์ผ๊ณ ์ ๋งํ๋ ์์ฒ )
๐ฃ ์์ฒ : ์๋ ๋ฆฌ๋ ๋! ์ ์ด์ ๋ฐฐ์ด ๋๋ก Next.js App Router ์
์
๋ค ๋๋๊ฑฐ๋ ์? ๊ทธ๋ฆฌ๊ณ ์๋ฒ ์ปดํฌ๋ํธ ์์์ fetch ์น๋๊น ํ๋ฉด์ด 0์ด ๋ง์ ๊ฒ๋ ๋นก๋นกํ๊ฒ ๋ ๋๋ง๋ผ์ ์ ์ ํํ
HTML ๋ฑ ๋จ์ด์ง๋ ๊ฑฐ ์์ ๊ฐ๋ํ์ด์!
๐ฆ ์ํธ: ๊ทธ๋ผ ์ฑ๊ณต์ ์ธ๋ฐ์? ๋ญ๊ฐ ๋ถ๋ง์ด์์ฃ ?
๐ฃ ์์ฒ : ์ ๊ทธ๊ฒ... ๊ทธ ์๋ฒ์์ ๊ทธ๋ฆฐ ํ๋ฉด ์์๋ค๊ฐ "์ข์์ ๋ฒํผ"์ด๋ ๋ฌดํ ์คํฌ๋กค ๋ฃ์ผ๋ ค๊ณ ์์ ์ปดํฌ๋ํธ(Client Component)๋ก ์กฐ๊ฐ ํ์ ๋จ๊ฑฐ๋ ์? ๊ฑฐ๊ธฐ ์์ ๋ฆฌ์กํธ ์ฟผ๋ฆฌ useQuery(['posts'])๋ฅผ ์ ์ธํ๋๊น, ์ ์ ๊ฐ ํ์ด์ง ๋ค์ด์์ ํ๋ฉด ๋ณด์๋ง์ ๋ฐฑ๊ทธ๋ผ์ด๋ API๋ฅผ ๋ค์ ๋๋ ค์! ๋ถ๋ช
ํ ๊ทธ posts ๋ฐ์ดํฐ ์์ชฝ 100์ค์ง๋ฆฌ ๋ถ๋ชจ ์๋ฒ ์ฃผ๋ฐฉ์์ ๋ค ๊ตฌ์์ HTML๋ก ๋ด๋ฆฐ ์ต์ ๋ฐ์ดํฐ์ธ๋ฐ, ํ๋ก ํธ ์์ง ์ผ์ง์๋ง์ ์ง๊ฐ ๋ชจ๋ฅด๊ณ ๋ค์ ๊ฐ์ ธ์ค์์์! ์๋ฒ ๋ถํ ๋ฏธ์น ๊ฑฐ ์๋์์?!
๐ฆ ์ํธ: ์ํ, ์๋ฒฝํฉ๋๋ค ์์ฒ ๋. ์๋ฒ์ ์ฃผ๋ฐฉ์์ ๋ฐ์ดํฐ ์ด์ฌํ ํผ ์์ ์๋ฆฌ๋ฅผ ๊ตฌ์๋๊ณ , ์ ์ ํ๋ก ํธ์๋ ์์ ์บ์ ๊ธ๊ณ (QueryCache) ์๊ฒ๋ "์๋ฒ๊ฐ ๋ฐฉ๊ธ ๋ฐ์ดํฐ ๊ตฌ์๋จ์ผ๋ ๋ ์ด๊ฑฐ ์๊ณ ์์ด๋ผ" ๋ผ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์
์์ผ์ฃผ์ง ์์๊ตฐ์.
๊ฐ์ฅ ์ค์ํ๊ณ ๋์ด๋ ์๋ ๋๋ฏธ์ ์ฅ, Hydration (์ํ) ์ initialData ์ ์ธ๊ณ์ ์ค์ ๊ฑธ ํ์ํฉ๋๋ค.
๐ค ์ ์์์ผ ํ๋๊ฐ: ์บ์ ์ฌ๊ฐ์ง๋ (Cache Blind Spot)
Next.js์ ์๋ฒ ์ปดํฌ๋ํธ(RSC)์์ ๋ถ๋ฆฌ๋์ผ DB๋ฅผ ์ฐ๋ฌ ์ต์ ์ ์์ ํ ๋ฐ์ดํฐ๋ฅผ ๋ค ๊ฐ์ ธ์์ HTML์ ๊ทธ๋ ธ๋ค๊ณ ๊ฐ์ ํฉ์๋ค. ์ด ํ๋ฉด ๊ป๋ฐ๊ธฐ(HTML)๋ฅผ ์ ์ ์ ๋ชจ๋ฐ์ผ ํฐ์ผ๋ก ๋นก ๋์ก์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ทธ ํฐ ์์๋ React Query๋ผ๋ ๋
์์ ์ธ ํด๋ผ์ด์ธํธ ๋งค๋์ ๊ฐ ์๋ก ๋์ ๋น๋๋ค.
๋
์์ด ์บ์ ๊ธ๊ณ ๋ฌธ์ ์ด์ด๋ณด๋...? ํ
๋น์ด์์ต๋๋ค.
์? ์๋ฒ๊ฐ HTML๋ง ์คฌ์ง, ํ๋ก ํธ์๋์ ์ฟผ๋ฆฌ ํด๋ผ์ด์ธํธ(๋ฉ๋ชจ๋ฆฌ) ์์ "๋ด๊ฐ ๋ฌด์จ ๋ฐ์ดํฐ๋ฅผ ์ผ๋์ง" ์ฃผ์
(Inject) ํด์ฃผ์ง ์์๊ธฐ ๋๋ฌธ์ด์ฃ .
๊ฒฐ๊ตญ React Query๋ "์ค ๋ง์ด ๊ฐ, ๋ฐ์ดํฐ๊ฐ ํ ๋น์๋ค? ๋ด๊ฐ ๋ค์ API ์ด์ ๊ฐ์ ธ์์ผ๊ฒ ๊ตฐ!" ํ๋ฉฐ ๋ฌด์๋ฏธํ ์ค๋ณต ๋คํธ์ํฌ ํธ๋ํฝ์ ์ ๋ฐํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฅผ ๋ง๊ธฐ ์ํด ์๋ฒ์์ ๋ด ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ ์บ์๋ก ์ ์ง์ด๋ฃ์ด ์ฃผ๋ ์ด๊ธฐ ๋ฐ์ดํฐ ์ฃผ์ ๊ธฐ์ ์ ๋ง์คํฐํด์ผ ํฉ๋๋ค.
๋ฐฉ๋ฒ์ ํฌ๊ฒ 2๊ฐ์ง์ ๋๋ค.
1. ์ ์ A: initialData (๊ฐ์ฅ ์ฝ๊ณ ์ง๊ด์ ์ธ Prop ์ ๋ฌ)
TkDodo์ ์ํฐํด #17์ ๋ณด๋ฉด ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ด ์ ์ผ ์ฝ์ต๋๋ค.
์ฐ๋ฆฌ๊ฐ RSC(์๋ฒ ์ฃผ๋ฐฉ) ์์์ ๋ฐ์ดํฐ๋ฅผ ๋ฑ ์ป์ด๋๋ค๋ฉด, ๊ทธ๊ฑธ ์์ ์กฐ๊ฐ ์ปดํฌ๋ํธ(Client Component) ํํ
props๋ก ๋ด๋ ค์ฐ์ ๋ค, ์ฟผ๋ฆฌ์ initialData ์ค์ ์ฌ๋กฏ์ ํญ ๋ผ์ ๋ฃ๋ ๋ฐฉ๋ฒ์
๋๋ค.
// ๐ app/board/page.tsx (์๋ฒ ์ฃผ๋ฐฉ - RSC)
import { getPosts } from '@/api/posts'
import { BoardClient } from './board-client'; // ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ (use client)
export default async function BoardPage() {
// 1๏ธโฃ ์๋ฒ์์ DB๋ฅผ ์ง๋นต์ผ๋ก ์ฐ๋ฌ ๋ฐ์ดํฐ๋ฅผ ์๋ฒฝํ๊ฒ ๊ตฌ์๋
const postsFromServer = await getPosts();
// 2๏ธโฃ ๊ทธ ๊ทํ ๋ฐ์ดํฐ๋ฅผ ํ๋กํผํฐ(Prop)๋ก ํ๋ฐฐ๋ฅผ ์ธ์ ์์์๊ฒ ๋์ง๋ค!
return <BoardClient initialPosts={postsFromServer} />
}// ๐ app/board/board-client.tsx (ํด๋ผ์ด์ธํธ ํฐ - CSR)
'use client'
import { useQuery } from '@tanstack/react-query';
import { getPosts } from '@/api/posts';
export function BoardClient({ initialPosts }: { initialPosts: Post[] }) {
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => getPosts(),
// 3๏ธโฃ ๐ ๋ง๋ฒ์ ํต์ฌ: "Query์ผ! ๋ด ์๋ง(์๋ฒ ์ฃผ๋ฐฉ)๊ฐ ๋ฐ์ดํฐ ์ธ์ฃผ์
จ์ด! ์บ์ํต์ ์ผ๋จ ์ด๊ฑฐ๋ถํฐ ๋ฐ์๋ฃ๊ณ ์์ํด!"
initialData: initialPosts,
});
return (
<ul> {/* ๊น๋นก์ 0%, API ๋ถํ์ ์ค๋ณต ํธ์ถ 0๋ฐฐ ํญ๋ฐ์ ์ฑ๋ฅ */}
{data.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
)
}๐ก ์ฅ๋จ์
- ์ฅ์ : ๊ฐ๋ฐ์๊ฐ ์ง๊ด์ ์ผ๋ก ์ดํดํ๊ธฐ ์์ฒญ๋๊ฒ ์ฝ๋ค.
- ๋จ์ : ์ปดํฌ๋ํธ ํธ๋ฆฌ๊ฐ ๋๋ฌด๋ ๊น๋๋ค. ๋ฐ์ดํฐ๋ฅผ 3๋จ๊ณ, 4๋จ๊ณ ์๋ ๋ํธ๋จธ๋ฆฌ์ ์๋ ์กฐ๋ง๋งํ ๋ฆฌ์คํธ ์ปดํฌ๋ํธํํ
์ ๋ฌํ๋ ค๋ฉด
Props Drilling์ง์ฅ์ด ํผ์ณ์ง๋๋ค.
2. ์ ์ B: <HydrationBoundary> (์ง์ ํ ์ํคํ
์ฒ์ ๊ฝ)
๊ทธ๋์ ํ์ํ ๊ถ๊ทน๊ธฐ๊ฐ ํผ๊ฒฉ ๋์ Hydration(Dehydrate/Hydrate) ๋ฉ์ปค๋์ฆ์
๋๋ค.
์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ค ๋ด ๋ค์์, ๊ทธ ๋ฐ์ดํฐ๋ฅผ ํต์กฐ๋ฆผ(DehydrateState)์ผ๋ก ๊ฝ๊ฝ ๊นกํต ์์ถ ์์ผ์ ๋ธ๋ผ์ฐ์ ๋ก ๋ด๋ ค๋ณด๋
๋๋ค.
ํฐ์ ๋์ฐฉํ ๊นกํต์ <HydrationBoundary> ๋ผ๋ ์ ์๋ ์ธ์ง๋ฅผ ๋ง๋์ ํ! ํ๊ณ ํฐ์ง๋ฉด์ ์ ์ญ ์บ์ ๊ธ๊ณ (QueryClient)์ ๊ตฌ์๊ตฌ์ ๋ชจ๋ ๋ฐฉ๋ฐฉ๊ณก๊ณก์ผ๋ก ๊ทธ ๋์(๋ฐ์ดํฐ)๋ฅผ ํผํธ๋ ค๋ฒ๋ฆฝ๋๋ค(Hydrate).
Props๋ก ํ๋ฐฐ ์์ ์จ์ฒ๋ผ ์ผ์ผ์ด ์ ๋ฌํ ํ์๊ฐ ์์ ์ฌ๋ผ์ง๋ ๊ฒ๋๋ค! (์ค๋ก์ง ์บ์ ์ด๋ฆํ์ธ queryKey ๋ง์ผ๋ก ๋ค ๋นจ์๋ค์)
// ๐ app/board/page.tsx (์๋ฒ ์ฃผ๋ฐฉ - RSC)
import { HydrationBoundary, dehydrate, QueryClient } from '@tanstack/react-query'
import { getPosts } from '@/api/posts'
import { BoardClient } from './board-client' // ์ด๊ฑด ์ด์ Prop์ด ์ ํ ํ์ ์์ง!
export default async function BoardPage() {
// 1๏ธโฃ ์ด ์์ฒญ ๋จ ํ ๋ฒ์๋ง ์ฐ์ด๋ 1ํ์ฉ ๋น ๊นกํต ์์ฑ
const queryClient = new QueryClient();
// 2๏ธโฃ ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ถฉ๋ถํ ๋น๊ฒจ์(Prefetch) ์๋ฒ์ฉ ๋น ๊นกํตํต ์บ์ ์์ ๊ฐ๋ ์ฑ์ด๋ค! (queryKey ๋ช
์ฌ!!)
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
});
return (
// 3๏ธโฃ dehydrate(๊นกํต ์์ถ๊ธฐ)๋ฅผ ์ด์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ด๋ฒ๋ฆฐ๋ค!!
// ์ ์๋ ์ธ์ง(Boundary) ๊ฐ ๋์๊ฐ๋ ์ด ์๋์ชฝ(์์) ์์ญ์ ์ด์ ์ ๋ค์ ์ํ ๋ค.
<HydrationBoundary state={dehydrate(queryClient)}>
<BoardClient />
</HydrationBoundary>
)
}์ด์ ํด๋ผ์ด์ธํธ ์ชฝ์ ๋ณผ๊น์? ๋๋ฌผ์ด ์์นต ๋ ๋งํผ ๊น๋ํด์ง๋๋ค.
// ๐ app/board/board-client.tsx (ํด๋ผ์ด์ธํธ - CSR)
'use client'
import { useQuery } from '@tanstack/react-query'
import { getPosts } from '@/api/posts'
export function BoardClient() {
// ๐ ๋!!! Prop์ด ์์ต๋๋ค! initialData๋ ์์ต๋๋ค!
// ์๊น ๋ฐ์์ ์ ์๋ ์ธ์ง(Boundary)๊ฐ ํฐ์ง ๋ ์ด๋ฏธ ์ด ๋ธ๋ผ์ฐ์ ์ ์ญ ์บ์ ์์
// ['posts'] ๋ผ๋ ํค ๊ฐ์ผ๋ก ์บ์๊ฐ "์์ฃผ ๊ฝ ์ฐจ" ๋ค์ด๊ฐ๊ธฐ ๋๋ฌธ์
๋๋ค.
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => getPosts()
});
return <div>{data.length}๊ฐ ๊ทธ๋ฆฌ๊ธฐ ์๋ฃ</div>
}์ด ํจํด์ด ๋ฐ๋ก Next.js App Router์ React Query๋ฅผ ๊ฒฐํฉ์ํค๋ ๊ถ๊ทน์ ์๋๊ฒ์ ์ํคํ
์ฒ ์
๋๋ค. ์ด๋ค ์์ ์ปดํฌ๋ํธ ๊น์ํ ๊ณณ์์ useQuery(['posts']) ๋ฅผ ์ณ๋ถ๋ฅด๋๋ผ๋ ์บ์์ ์ด๋ฏธ ๊ฟ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ผ์ ธ ์์ด์ ๋ฌด์ค๋ณต ๋ฌด๋ก๋ฉ ์๋ฒฝ ์ฑ๋ฅ์ด ๋์ต๋๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์, ๋ฏธ์น ๊ฑฐ ์๋์ผ...? ๋ ๋ ์ด์ Next.js ํฌ๊ธฐํ๊ณ ์ ํต SPA๋ก ๋์๊ฐ ๋ปํ๋๋ฐ.
Props ๋ก ๋๊ธฐ๋ ค๋ค๊ฐ depth ๋๋ฌด ๊ธธ์ด์ ธ์ ์ธ๊ณ ์์๋๋ฐ, ์๋ฒ์์ ํ๋ฆฌํ์น(prefetchQuery) ๋๋ ค ๋ฐ๊ณ Boundary๋ก ๊ฐ์ธ์ ๋ธ๋ผ์ฐ์ ์บ์์ ๊ณต์ค ํฌํ(AirDrop) ์์ผ๋ฒ๋ฆฌ๋ ๋ฐฉ์์ ์ง์ง... ๊ธฐ์ ์ ๋ญ๋ง ๊ทธ ์์ฒด๋ค.
๐ก ์ค๋์ ๊ตํ: "์๋ฒ ์ฃผ๋ฐฉ์์ ๋ง์๋ ์๋ฆฌ๋ฅผ ํฝ์ ํ๋ค๋ฉด ํด๋ผ์ด์ธํธ ์บ์ ๊ธ๊ณ ์๋ ๊ทธ ๋ ์ํผ๋ฅผ ์ธ์์ธ๊ณ(Hydration) ํด์ฃผ์. ๊ทธ๋์ผ ํ๋ก ํธ๊ฐ ๋ฉ์ฒญํ๊ฒ API๋ฅผ ๋ ์ค๋ณตํธ์ถํ๋ ๋์ฐธ์ฌ๋ฅผ ๋ง์ ์ ์๋ค!"
๋๋์ด Basic ๊ธฐ์ด ๊ฐ์ด๋๋ผ์ธ 10๊ฐ๊ฐ ๋๋ฌ๋ค. ์์งํ ์ด 10๊ฐ๋ง ์๋ฒฝํ๊ฒ ์๊ณ ์ฒด๋ํด๋ ์ด๋ ๊ฐ์ ์คํ๊ฒํฐ ์์ค ํต์ผ๋ก ๋ค์๋ ๋ฏผํ๋ ์ ๋ ์ ๋ผ์น ๊ฑฐ ๊ฐ๋ค. ์ํธ ๋ฆฌ๋ ๋์ด ๋ด์ผ๋ถํด ๋ฌดํ ์คํฌ๋กค ๊ฐ์ Advanced ์์ญ(์ฌํ 7๊ฐ) ํ ๊ฑฐ๋ผ๋๋ฐ, ์ผ๋จ ์ค๋๊น์ง ๋๊ฐ๋ฆฌ์ ๋ฐํ ์ง๋ฆฟํจ ์ฆ๊ธฐ๋ฉด์ ๊ฟ์ ์์ผ์ง ใ ใ ใ ใ . ๐ถ
๐ ๋ฐฐ์ด ๋ด์ฉ ์ ๊ฒํ๊ธฐ (Quiz)
Q. ์์ฒ ์ด๊ฐ ์๋์ค๋ฝ๊ฒ <HydrationBoundary> ํจํด์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋๋ฐ, ์ปดํฌ๋ํธ ์ง์
์ฆ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋คํธ์ํฌ ์ฌํธ์ถ(Refetching) ์ด ํ ๋ฒ ๋ ๋ฐ์ํ๋ ๊ฑธ ๋ชฉ๊ฒฉํ์ต๋๋ค. ์ฆ, ์๋ฒ ๋ ๋๋ง์ ์ฑ๊ณตํ์์๋ ํด๋ผ์ด์ธํธ์์ ํ ๋ฒ ๋ค์ ์๋ ๊ธฐ์ดํ ๋ฒ๊ทธ์ธ๋ฐ, ์์ธ์ด ๋ฌด์์ผ๊น์? ์ด ์ต์
์ ๊ธฐ๋ณธ๊ฐ ์ฒ ํ์ ๋น์ถ์ด ์ค๋ช
ํด๋ณด์ธ์.
โ
์ ๋ต: ์๋ฒ์์ ํ๋ฆฌํ์นํ์ฌ ๋๊ฒจ์ค ๋ฐ์ดํฐ(ํต์กฐ๋ฆผ)์ 'staleTime'์ด 0(๊ธฐ๋ณธ๊ฐ)์ด์๊ธฐ ๋๋ฌธ์
๋๋ค.
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
: ์๋ฒ๊ฐ ์๋ฌด๋ฆฌ ์ด์ฌํ
prefetchQuery๋ก ๋ฐ์ดํฐ๋ฅผ ์ฑ์์ฃผ๊ณ , ํด๋ผ์ด์ธํธ๋ก Hydrate(์ํ) ๋๊ฒจ์ค ๋ดค์ React Query์ ์ ์ ๋(staleTime) ๊ธฐ๋ณธ๊ฐ์ 0์ด์ ๋๋ค! ๋ธ๋ผ์ฐ์ ์ ์ฟผ๋ฆฌ ๋ ์์ ๋์ ๋จ์๋ง์ "์ค ๋ฐ์ดํฐ ๋ค์ด์๋ค?(์คํผ๋ ๋ง์, ์ผ๋จ ํ๋ฉด ๊ทธ๋ฆผ) ์ ๊น, ๊ทผ๋ฐ ์ด๊ฑฐstale(์ํ ๋นต)์ํ์์? ๋น์ฅ ์๋ฒ์ ๋ท๋จ์์ ๋ค์ ๊ฐ์ ์ง์ง ์ต์ ๋ง๋์ง ๋ฌผ์ด๋ด์ผ๊ฒ ๋ค!" ๋ผ๋ฉฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ฆฌํจ์นญ์ ์กฐ์ฉํ ์ํํฉ๋๋ค. - ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋, ์ด๊ธฐ Hydrate ์งํ ๋ถํ์ํ ๋ท๋จ ๋ฆฌํจ์นญ(Refetch)๋ฅผ ๋ง๊ณ ์ถ๋ค๋ฉด, ์๋ฒ์์
Prefetchํ ๋๋ผ๋๊ฐ ์ต์๋จ QueryClient ์ธ์คํด์ค๋ฅผ ์ฐ์ด๋ผ ๋staleTime: 60 * 1000(1๋ถ ์ ๋) ์ ๋๋ํ ์ ์ ๋ ์ ํต๊ธฐํ์ ๊ฐ์ ๋ก ๋ถ์ฌํด์ฃผ์ ์ผ๋ง ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ ์์ฌ์ ๊ฑฐ๋๊ณ ๋คํธ์ํฌ ๋ก๋๋ฅผ ์ ๋ฌํ๊ฒ ์๋๋๋ค!" - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: ์ํ์ ๋ง์ง๋ง ์กฐ๊ฐ์ ์ธ์ ๋ ๋๋ํ ์ ํต๊ธฐํ(
staleTime) ๋ณด์ฅ!