๐ก 03. Query Lifecycle๊ณผ ๋ ๋๋ง ์ต์ ํ
๐ ๊ฐ์
staleTime๊ณผ gcTime์ ์ฐจ์ด๋ฅผ ์๋ฒฝํ ํต๋ฌํ๊ณ , Structural Sharing์ ํตํด ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ง์๋ด๋ ์๋ฆฌ๋ฅผ ์ดํดํฉ๋๋ค.
๐ ๋ชฉ์ฐจ
- โ๏ธ ์์ฒ ์ด์ ๊ณ ๋ฏผ: "์ ์๊พธ ๋ค์์ ์๋ก๊ณ ์นจ์ด ๋๋ ๊ฑธ๊น์?"
- ๐ค ์ ์์์ผ ํ๋๊ฐ: ์บ์ ์๋ฒ์ ์ ์ ํ์ ํ๊ธฐ
- 1.
staleTimevsgcTime: ์ ๋ ํท๊ฐ๋ฆฌ์ง ์๋ ๋น์ - 2. ์์ฒญ๋ ๋ง๋ฒ: Structural Sharing๊ณผ ๋ฆฌ๋ ๋๋ง ๊ฐ์ด
- ๐ ๋ฐฐ์ด ๋ด์ฉ ์ ๊ฒํ๊ธฐ (Quiz)
"์์ฒ ๋,
staleTime๊ณผgcTime๊ฐ์ด ๋๊ฐ์ ๊ฒ ๋ง์ด ๋๋์? ์บ์๋ฅผ ๋ฒ๋ฆฌ๊ณ ์๋๋ฐ ์ ์ํ ๋นต์ ๋ค๊ณ ์์ฃ ?"
โ๏ธ ์์ฒ ์ด์ ๊ณ ๋ฏผ: "์ ์๊พธ ๋ค์์ ์๋ก๊ณ ์นจ์ด ๋๋ ๊ฑธ๊น์?"
(๋ชฉ์์ผ ์คํ, ํฌ๋กฌ ๋๋ฒ๊ฑฐ ๋คํธ์ํฌ ์ฐฝ์ ์ ์ฌํ ๋ค์ฌ๋ค๋ณด๋ฉฐ ๋นํฉํ๋ ์์ฒ )
๐ฃ ์์ฒ : ์๋, ๋ฆฌ๋ ๋! ๋ฐฉ๊ธ ์ ๊ฐ React Query ๋์
ํ๋ฉด์ staleTime์ ์์ 1์๊ฐ์ผ๋ก ์์ฐฝ ๋๋ ค๋จ๊ฑฐ๋ ์? ์๋ฒ์ 1์๊ฐ ๋์ ๋ฌด์กฐ๊ฑด ์ ์น๊ณ ์บ์ ์ฐ๊ฒ ๋ค๊ณ ์. ๊ทผ๋ฐ ์ ๊ฐ ๋ธ๋ผ์ฐ์ ํญ์ ์ ๊น ๋ค๋ฅธ ๋ฐ ๊ฐ๋ค ์๋๋ ๋ค์์ ๋ ๋คํธ์ํฌ API fetch ๊ฐ ํํ ์ฐํ๊ณ ์์ด์ ใ
ใ
! ๋๋์ฒด ์ด์ ๊ฐ ๋ญ๊น์? ์ ์ค์ ์ด ๋ฌด์๋นํ๋ ๊ธฐ๋ถ์ด์์.
๐ฆ ์ํธ: ์ค์ ์ด ๋ฌด์๋นํ๋ ๊ฒ ์๋๋๋ค. ์์ฒ ๋์ด ์ง๊ธ "์ ์ ๋(staleTime)" ์ "์ ํต๊ธฐํ(gcTime)" ์ด๋ผ๋ ๋ ๊ฐ์ง ์๋ช
์ฃผ๊ธฐ๋ฅผ ์๋ฒฝํ ํผ๋ํ๊ณ ๊ณ์ ๊ฑฐ๋ค์.
๊ฒ๋ค๊ฐ ์์ฒ ๋์ ์ฝ๋์์๋ ๋ฐ์ดํฐ๊ฐ ํ๋๋ ์ ๋ฐ๋์๋๋ฐ ์ธ๋ฐ์์ด ์ ์ฒด ๋ชฉ๋ก์ด ๋ฆฌ๋ ๋๋ง(Re-render) ๋๊ณ ์์ด์. React Query๊ฐ ๋ด๋ถ์ ์ผ๋ก ์ผ๋ง๋ ๋ฌด์์ด ์ต์ ํ ๋ฉ์ปค๋์ฆ์ ๋๋ ค์ฃผ๋์ง ๋ชจ๋ฅด๊ณ ์ฐ๊ณ ๊ณ์ ๊ฒ ๋ถ๋ช ํฉ๋๋ค.
๐ค ์ ์์์ผ ํ๋๊ฐ: ์บ์ ์๋ฒ์ ์ ์ ํ์ ํ๊ธฐ
์ฐ๋ฆฌ๊ฐ React Query๋ฅผ ์ฐ๋ ๊ฑด, ๋คํธ์ํฌ ํ์นญ ํ์๋ฅผ ์ค์ฌ์ ์๋ฒ ๋ถํ๋ฅผ ๋ง๊ณ , ์ ์ ์๊ฒ๋ 0์ด ๋ก๋ฉ ๊ฒฝํ์ ์ฃผ๊ธฐ ์ํจ์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ๋ผ์ดํ์ฌ์ดํด(Lifecycle)์ ๋ชจ๋ฅด๋ฉด,
- "๋ ๋ถ๋ช ํ ์บ์๋ฅผ ์ฐ๋ ค๊ณ ๋๋๋ฐ ์ ์๊พธ API ์ฝ์ด ๋ ์๊ฐ๊น?" (๋ถํ์ํ ๊ณผ๊ธ ๋ฐ์)
- "์ ๋ชจ๋ฌ ์ฐฝ๋ง ์ด์๋ค ๋ซ์๋๋ฐ ๋ฆฌ์คํธ 100๊ฐ๊ฐ ๋ค ๋ฆฌ๋ ๋๋ง ์น์ง?" (์ฑ๋ฅ ํ๋ฝ)
๊ฐ์ ์ ์ํ์ ์ง๋ฉดํฉ๋๋ค.
์ด ๋จ์์์๋ 5๋
์ฐจ ์ค๋ฌด์๊ฐ ๊ฐ์ฅ ๋จผ์ ๋ฌผ์ด๋ณด๋ ๊ธฐ์ ๋ฉด์ 1์์ ์ง๋ฌธ์ธ staleTime๊ณผ gcTime์ ๋น์ ์ ๋จธ๋ฆฟ์์ ์๋ฒฝํ ์๊ฒจ ๋ฃ๊ฒ ์ต๋๋ค.
1. staleTime vs gcTime: ์ ๋ ํท๊ฐ๋ฆฌ์ง ์๋ ๋น์
React Query์ ๋ํดํธ(๊ธฐ๋ณธ๊ฐ)๋ ์์ฒญ๋๊ฒ ๋ณด์์ ์ด๊ณ ์๋ฆฌํฉ๋๋ค.
๋จผ์ ์ด๊ฑธ ์ธ์ฐ๊ณ ์์ํ์ธ์. "๋ํดํธ staleTime = 0", "๋ํดํธ gcTime = 5๋ถ"
๐ staleTime : ์๋นต์ ์ ์ ๋ (Data Freshness)
stale์ '์ํ, ํดํดํ' ์ด๋ผ๋ ๋ป์
๋๋ค.
๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค์๋ง์ ์ด ์๋นต์ ์ผ๋ง๋ ์ ์ ํ ์ํ๋ฅผ ์ ์งํ ๊น์?
React Query์ ๊ธฐ๋ณธ๊ฐ์ 0, ์ฆ ๋ฐ์์จ ์ฆ์ ๋ฐ๋ก ์ํ(Stale) ์๋นต ์ทจ๊ธ์ ํฉ๋๋ค.
- ๋ง์ฝ
staleTime: 5 * 60 * 1000(5๋ถ) ์ด๋ผ๋ฉด?- ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๊ณ 5๋ถ ๋์์ ์์ ์ ์ (Fresh)ํฉ๋๋ค.
- ์ด ๊ธฐ๊ฐ ๋์ ์ ์ ๊ฐ ๋ค๋ฅธ ํญ์ ๊ฐ๋ค๊ฐ ๋ค์ ์ค๊ฑฐ๋, ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ์ด์ด๋ ์ ๋๋ก ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ค์ ๋คํธ์ํฌ(Fetch) ์์ฒญ์ ์์ง ์์ต๋๋ค!
- ์์ฒ ์ด๊ฐ ๊ฒช์๋ "ํญ ๋ฐ๊ฟจ๋๋ฐ ์๊พธ ํ์นํด์!" ๋ ์ด ์ ์ ๋ ์๊ฐ์ ์ ๋๋ก ์ ์คฌ๊ฑฐ๋, 0์ผ๋ก ๋์๊ธฐ์ ๋ฐ์ํ ๊ฒ๋๋ค. (Stale ์ํ์ผ ๋, ํฌ์ปค์ค๊ฐ ๋์์ค๋ฉด ๋ฌด์กฐ๊ฑด ๋ค์ ์ ์ค๋น๋ฅผ ํ๋๊น์)
๐๏ธ gcTime : ๋์ฅ๊ณ ์ ํต๊ธฐํ (Garbage Collection Time)
์ด๊ฑด cacheTime์ด๋ผ๋ ์ด์ v4 ์์ ์ ์ด๋ฆ์์ gcTime์ผ๋ก ๋ฐ๋์์ต๋๋ค. (์คํด ๋ฐฉ์ง)
์ด Query๋ฅผ ๋ฐ๋ผ๋ณด๋ ์ต์ ๋ฒ(์ปดํฌ๋ํธ)๊ฐ ํ๋ฉด์์ ํ ๋ช
๋ ์ ๋จ๊ณ ๋ชจ๋ ์ธ๋ง์ดํธ(Unmount) ๋์์ ๋๋ถํฐ ์นด์ดํธ๋ค์ด ์ด ์์๋ฉ๋๋ค.
- 5๋ถ ๋ค, (๊ธฐ๋ณธ๊ฐ) "์๋ฌด๋ ์ด ์ ์ ๋ ํ์ธ ์ ํ ์ง 5๋ถ์ด๋ ๋๋ค? ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ค, ์ด ๋นต์ ์ฐ๋ ๊ธฐํต(Garbage)์ผ๋ก!" ํ๊ณ ํ๋๋์คํฌ(๋ฉ๋ชจ๋ฆฌ ์บ์)์์ ์น ๋ ๋ ค๋ฒ๋ฆฝ๋๋ค.
- ๊ทธ ์ดํ ๋ค์ ์ปดํฌ๋ํธ๋ฅผ ๋์ฐ๋ฉด ์์ ๊ทน์ด๊ธฐ ํ๋ ๋ก๋ฉ(
isLoading === true) ์ํฉ์ผ๋ก ํ๊ทํฉ๋๋ค.
โผ๏ธ ์๋์ด์ ์กฐ์ธ:
์ค๋ฌด์์staleTime์gcTime๋ณด๋ค ๊ฐ๊ฑฐ๋ ๊ฐ์ ๋ก ๋ ๊ธธ๊ฒ ์ค์ ํ๋ฉด ํ๋ฉธ์ ๋ถ๋ฆ ๋๋ค.
"๋ฐ์ดํฐ ์ ์ ๋๊ฐ 1์๊ฐ ๋จ์๋๋ฐ, ๋ฉ๋ชจ๋ฆฌ์์ 5๋ถ ๋ง์ ์ง์๋ฒ๋ ค๋ผ" ๋ผ๋ ๊ธฐ๊ดดํ ์ ์ฑ ์ด ๋๊ธฐ ๋๋ฌธ์ด์ฃ . ํญ์gcTime์ดstaleTime๋ณด๋ค ํฌ๊ฒ ์ค์ ํด์ผ ์บ์ ์์คํ ์ด ์จ์ ํ ๋์ํฉ๋๋ค.
2. ์์ฒญ๋ ๋ง๋ฒ: Structural Sharing๊ณผ ๋ฆฌ๋ ๋๋ง ๊ฐ์ด
์์ฒ (์ ์ ): "๋ฆฌ๋ ๋! ์๊น ๋ฐ์ดํฐ ์ ๋ฐ๋๋ฉด ๋ฆฌ๋ ๋๋ง ์ ์ผ์ด๋๋ค ํ์ จ๋๋ฐ ๊ทธ๊ฒ ๋ฌด์จ ์๋ฆฌ์ธ๊ฐ์? API ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์๋ฉด ๋ฌด์กฐ๊ฑด ์ ๊ฐ์ฒด ๋ฐ์ผ๋๊น ๋ฆฌ์กํธ๋ ๋ค๋ฅด๋ค๊ณ ํ๋จํด์ ๋ฌด์กฐ๊ฑด ์๋ก๊ณ ์นจ ์น๋ ๊ฑฐ ์๋๊ฐ์?"
๐ฆ ์ํธ: "React Query ๋ด๋ถ์ ์ต๊ณ ๋ง๋ฒ ๊ตฌ์กฐ์ธ Structural Sharing (๊ตฌ์กฐ์ ๊ณต์ ) ์ ์ ํ ๋ชจ๋ฅด์๋๊ตฐ์."
๋ง์ฝ 100๊ฐ์ ๋ฆฌ์คํธ๊ฐ ์์ต๋๋ค. ํ๋ฉด์์ ๋ค๋ฅธ ํญ ๊ฐ๋ค ์์ ๋ฐฑ๊ทธ๋ผ์ด๋ ํด๋ง(isFetching)์ด ์ผ์ด๋ฌ์ต๋๋ค. ์๋ฒ์์ ํต์งธ๋ก 100๊ฐ์ ๋ฆฌ์คํธ๋ฅผ ์๋ก ๋ด๋ ค๋ณด๋๋ค๊ณ ๊ฐ์ ํฉ์๋ค. ์ด ์ค, 1๋ฒ์งธ ๊ธ์ ์ ๋ชฉ ๋ฑ ํ๋๋ง ๋ฐ๋๊ณ ๋๋จธ์ง 99๊ฐ๋ ์๋ฒฝํ ๋๊ฐ์ต๋๋ค.
// ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์นญ ์ด์ ์บ์
{ "data": [{ "id": 1, "title": "ํ ๋ผ" }, { "id": 2, "title": "๊ฑฐ๋ถ์ด" }] }
// ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์นญ ๊ฒฐ๊ณผ (์๋ก์ด ๊ฐ์ฒด ๋ฉ์ด๋ฆฌ)
{ "data": [{ "id": 1, "title": "๋ฌด์ ํ ๋ผ" }, { "id": 2, "title": "๊ฑฐ๋ถ์ด" }] }๋ณดํต์ useEffect + setState ๋ผ๋ฉด ์ด ๊ฑฐ๋ํ ๋ญํ
์ด๋ฅผ ํต์งธ๋ก ๋ฎ์ด์์์ 100๊ฐ ์ปดํฌ๋ํธ๊ฐ ์ ๋ถ ๋ฏธ์น๋ฏ์ด ๋ฒ์ฉ๊ฑฐ๋ฆฌ๋ฉฐ ๋ฆฌ๋ ๋๋ง ๋์์ ๊ฒ๋๋ค (Redux๋ ๋ง์ฐฌ๊ฐ์ง).
ํ์ง๋ง React Query๋ ๊ทธ๋ ์ง ์์ต๋๋ค.
- ์๋ฒ์์ ์ ์๋ต์ด ์ด.
- React Query๊ฐ ์์ฃผ ๊น์ ๊ณณ์์ ๋ฐฉ๊ธ ์จ ์ ๋ฐ์ดํฐ ๋ญ์น์ ๊ธฐ์กด ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ๋นจ๋ฆฌ ํ ๊ฒน ํ ๊ฒน ์ํํ๋ฉฐ Deep Equal (๊น์ ๋น๊ต) ์ ์ํํจ.
- ์ด๋ผ? 2๋ฒ ๊ฑฐ๋ถ์ด ๊ฐ์ฒด๋ ์์ ๋ด์ฉ์ด ์๋ฆฟ์ ํ๋ ์ ํ๋ฆฌ๊ณ ๋๊ฐ๋ค? -> ์๋ก ์จ 2๋ฒ ๊ฐ์ฒด๋ฅผ ๊ณผ๊ฐํ ๋ฒ๋ฆฌ๊ณ , ์ด์ 2๋ฒ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ์ฐธ์กฐ(Reference) ์ฃผ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํฉ๋๋ค.
- ์ด? 1๋ฒ ํ ๋ผ ๊ฐ์ฒด๋ง ์ด๋ฆ์ด ๋ฐ๋์๋ค? -> ์๋ ์ ์ฃผ์๋ก ๊ฐ์๋ผ์.
- ๊ฒฐ๊ณผ: React๋ ์ฐธ์กฐ ์ฃผ์๊ฐ ์ ๋ฐ๋ 99๊ฐ์ ์ปดํฌ๋ํธ์ ๋ํด ์ ๋๋ก ๋ฆฌ๋ ๋๋ง์ ์ผ์ผํค์ง ์์ต๋๋ค. (์ต์ ํ ์ฑ๋ฅ ํญ๋ฐ ๐)
์ด๊ฒ์ด React Query๋ฅผ ์ผ์ ๋, ์๋ฌด ์ต์ ํ ์ ํ๋๋ฐ๋ ์ฑ์ด ์ค๋ฌด์คํ๊ณ ๊ฒฝ์ด๋กญ๊ฒ ๊ตฌ๋๋๋ ์ง์ง ์ด์ (์ฑ๋ฅ ์ด์ ) ์ ๋๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
ํ... ๋ ๊ทธ๋ฅ ํธํ๋ ค๊ณ React Query ์ผ๋๋ฐ, ์์์ Deep Equal ๋น๊ตํด์ ์ฐธ์กฐ ์ฃผ์๋ฅผ ๊ฐ์์ฃผ๋ฉฐ ๋ ๋๋ง ์ต์ ํ๊น์ง ํด์ฃผ๊ณ ์์๋ค๋ ์๋ฆ ๋๋ค;;
๐ก ์ค๋์ ๊ตํ: "stale(์ํ ๋นต ์ฌ๋ถ ํ๋จ)๊ณผ gc(์ฐ๋ ๊ธฐํต ์งํ ์ฌ๋ถ) ์๊ฐ์ ํ์คํ ๊ตฌ๋ถ! ๊ทธ๋ฆฌ๊ณ 100๊ฐ ๋ฐ์ดํฐ ํ์น ์ค 1๊ฐ๋ง ๋ฐ๋๋ฉด 1๊ฐ๋ง ๊ทธ๋ ค์ค๋ค! React Query ๋ฏธ์น ํจ์จ์ฑ ์ต๊ณ ์กด์."
์ํธ ๋์ด ๋ฌด์ฌํ๊ฒ ํญ ๋์ง ๋ง ์ค์ **"staleTime์ด๋ gcTime์ ์ธํธ๋ก ๋ง์ถ ๋ ํญ์ gcTime์ ๋ ๋๋ํ๊ฒ ์ก๋ ๊ฑธ ๋ช ์ฌํด๋ผ"**๋ผ๋ ๊ฒ ์ค๋ ์ ค ํฌ๊ฒ ์๋ฟ์๋ค. ์ง์ ๊ฐ์ ๋ด ํ๋๋ ์ฑ ์บ์ ํด๋ง ๊ธฐ๋ฅ๋ค ๋ค์ ์น ๋ค ์ก์๋ด์ผ๊ฒ ๋ค. ์ ๋๋ค! ๐โโ๏ธ๐จ
๐ ๋ฐฐ์ด ๋ด์ฉ ์ ๊ฒํ๊ธฐ (Quiz)
Q. ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ์์ฒ ์ด๊ฐ ์ฝ๋๋ฅผ ์งฐ์ต๋๋ค.
const { data } = useQuery({
queryKey: ['profiles'],
queryFn: fetchProfiles,
staleTime: Infinity, // "์ฑ์ ์ด์์จ์ฌ๋ ํ ์ ๋ ์บ์ ์ ์ํ๊ฒ!"
gcTime: 5 * 60 * 1000, // 5๋ถ ํ ์บ์ ๋ ๋ ค๋ฒ๋ฆผ
});์ด ์ฝ๋๋ก 'profiles' ํ์ด์ง๋ฅผ ๋ค์ด๊ฐ๋ค๊ฐ ๋ค๋ฅธ ํ๋ฉด์ผ๋ก ๋ฒ์ด๋ ์ง 10๋ถ์ด ์ง๋์ ๋ค์ 'profiles' ํ์ด์ง๋ก ๋์์์ ๋, ์ด๋ค ์ผ์ด ๋ฒ์ด์ง๊น์?
โ
์ ๋ต: ์ง๋
ํ ํ๋ ๋ก๋ฉ ์คํผ๋๊ฐ ๋๋ฉฐ ๋ฐ์ดํฐ๋ฅผ ์์ฐฝ ์ฒ์๋ถํฐ ๋ค์ ๊ฐ์ ธ์ค๊ฒ(Fetch) ๋ฉ๋๋ค.
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
:
staleTime์ ์์(Infinity)์ผ๋ก ๊ฑธ์ด ๋จ์ผ๋ ์ ๋๋ก ๋ค์ ๋คํธ์ํฌ ์์ฒญ์ ์ ์ ๊ฒ ๊ฐ์ฃ ? ์๋๋๋ค. ์๋ฌด๋ฆฌ ์ ์ ๋๋ฅผ ์์์ผ๋ก ๋ช ๋ช ํด ๋จ์ด๋, ์์ฒ ์ด๊ฐ ํ๋ฉด์ ๋ฒ์ด๋(์ธ๋ง์ดํธ) ํgcTime์ธ 5๋ถ์ด ๋์ด์๋ ์๊ฐ, ์บ์ ๋ฉ๋ชจ๋ฆฌ ์ฒญ์๋ถ๋ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์ฐจ๊ฐ์ด ์ฐ๋ ๊ธฐํต์ผ๋ก ๊ฐ์๋ฒ๋ฆฝ๋๋ค(Garbage collected). ์บ์ ํต ์์ฒด๊ฐ ํ ํ ๋น์ด๋ฒ๋ ธ๋๋ฐstaleTime์ด ๋ฌด์จ ์์ฉ์ด ์๊ฒ ์ต๋๊น? - ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋, ๋ช
์ฌํ์ธ์.
staleTime์ดgcTime์ ๋ฐ์ด๋์ผ๋ฉด ์๋ฌด ์์ฉ์ด ์์ด์! ๋์ฅ๊ณ ์ ํต๊ธฐํ์ด 5๋ถ์ธ๋ฐ ์๋นต ์ ์กฐ์ผ์ ์ ํจ๊ธฐ๊ฐ 10๋ ์ฐํ ์คํฐ์ปค ๋ถ์ฌ๋ด์ผ, ๊ฒฐ๊ตญ ๋์ฅ๊ณ ์์ 5๋ถ ๋ค์ ๋ค ๋ฒ๋ ค์ง๋๋ค." - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ:
staleTime(์ ์ ๋) <gcTime(๋์ฅ๊ณ ๋ณด๊ด์ผ์). ์ด ์ ๋ ๊ณต์์ ๋ฐ๋์ ์๊ธฐํ์ธ์!