ํฐ์คํ ๋ฆฌ ๋ทฐ
TodoList์ ๋ํ ์ผ ํ์ด์ง์ ํํ์ด์ง๋ฅผ ์ค๊ฐ๋ฉด์ ํ ์คํธํ staleTime ๊ณผ gcTime
![]() Home |
![]() Detail |
invalidateQuerise - ์ฟผ๋ฆฌ ๋ฌดํจํ
// Detail.jsx
const { id } = useParams();
const fetchDetail = async () => {
const response = await todoApi(`/todos/${id}`);
return response.data;
};
const { data, isLoading, error } = useQuery({
queryKey: ["todos", id],
queryFn: fetchDetail,
});
ํ -> ๋ํ ์ผ ํ์ด์ง๋ก ๋ค์ด๊ฐ๋ฉด params๋ก id๋ฅผ ์์ฒญํ์ฌ ํด๋น todo์ ์์ธ ๋ด์ฉ์ด ๋ฌ๋ค.

๋งจ ์ฒ์ ๋ํ
์ผ ํ์ด์ง์ ๋ค์ด๊ฐ๊ฒ ๋๋ฉด ๊ฐ์ ์๋ก ๋ถ๋ฌ์ค๊ธฐ ๋๋ฌธ์ '๋ก๋ฉ ์ค' ์ํ๊ฐ ๋๋ฉฐ Network ํญ์๋ ์๋ก์ด ๊ฐ์ด ์ ๋ถ๋ฌ์์ง๋ค.
์ดํ ์บ์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ๋๋ฌธ์ ๋ก๋ฉ๋ ๋ํ ์ผ ํ์ด์ง์ ๋ค์ด๊ฐ๋ฉด ๋ฐ๋ก ํ์ด์ง๊ฐ ๊ทธ๋ ค์ง๋ค.
โ์๋ก์ด ๊ฐ์ ์ถ๊ฐํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
// TodoForm.jsx
const { mutate } = useMutation({
mutationFn: addTodo,
onSuccess: () => {
queryClient.invalidateQueries(["todos"]);
},
});
mutate๋ก addTodo๋ฅผ ์คํํ๊ณ invalidate๋ก ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํํ๋ค.
'์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํ' ํ๊ธฐ ๋๋ฌธ์ ์๋ก์ด ์ฟผ๋ฆฌ๋ฅผ ๋ฐ์์์ ํ์ด์ง์ ์๋ก ๊ทธ๋ ค์ค๋ค๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํด์๋ค.
์๋๋ 3G ํ๊ฒฝ์์ ํ์ด์ง์ ๋ค์ด๊ฐ ์๋ก์ด ๊ฐ์ ๋ถ๋ฌ์จ ๋ค, todo๋ฅผ ์ถ๊ฐํ๊ณ ๋ค์ ๊ทธ ํ์ด์ง์ ๋ค์ด๊ฐ๋ณด๋ ์ํฉ์ด๋ค.
todo๋ฅผ ์ถ๊ฐํ๊ธฐ ๋๋ฌธ์ ์๋ก์ด ์ฟผ๋ฆฌ๋ฅผ ๋ฐ์์ค๋ ๊ฒ์ด๋ฉฐ, '๋ก๋ฉ ์ค...'์ด ๋ค์ ๋ฐ ๊ฒ์ผ๋ก ์์ํ๋ค.

ํ์ง๋ง ์์๊ณผ๋ ๋ค๋ฅด๊ฒ todo ์ถ๊ฐ ์ ๊ณผ ํ์ ํ์ด์ง ๋ณํ๊ฐ ์๋ค.
์ด ํ์์ ๊ณง ์๋ก์ด ๋ฐ์ดํฐ์ ํ์นญ์ด ์๋ ๊ธฐ์กด์ ์บ์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ ์จ๋ค๋ ์๋ฏธ์ผํ ๋ฐ...
๊ทธ๋ ๋ค๋ฉด '์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํ' ํ๋ค๋ ๊ฒ์ ์ด๋ค ๊ฒ์ผ๊น?
์ฐพ์๋ณด๋ invalidate๋ก ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํํ๋ค๋ ๊ฒ์ stale ์ํ๋ก ๋ง๋ค์ด์ค๋ค๋ ๊ฒ์ด์๋ค.
์ฆ, ์บ์ฑ๋ ๋ฐ์ดํฐ๋ ์ฌ๋ผ์ง์ง ์๊ณ staleํ ์ํ๋ก ๋ณํ๋ ๊ฒ๋ฟ์ด๊ธฐ ๋๋ฌธ์ ์ฟผ๋ฆฌ ๋ฌดํจํ ํ์๋ ๋ฐ๋ก ๋ฐ์ดํฐ๊ฐ ๋ถ๋ฌ์์ง๋ ๊ฒ์ด๋ค.
staleTime & gcTime


staleํ ์ํ๋ ๋ฐ์ ์จ ๋ฐ์ดํฐ๊ฐ ์ ์ ํ(fresh) ์ํ๊ฐ ์๋ ์ฉ์(stale) ์ํ์ธ ๊ฒ์ด๋ฉฐ ์บ์ฑ๋ ๋ฐ์ดํฐ๋ ๊ทธ๋๋ก ๋จ์์๋ค.
๋ฐ๋ผ์ ๋ฐ์ดํฐ๊ฐ staleํ ์ํ๊ฐ ๋๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํ์นญํ๋ค.
๐๐ปstale๋ ๋ฐ์ดํฐ๊ฐ ๋ฆฌํ์นญ๋๋ ์กฐ๊ฑด์ ๋ค์๊ณผ ๊ฐ๋ค.
1. staleTime์ด ์ง๋์ stale์ด ๋ ๊ฒฝ์ฐ
- staleTime์ด ๋ง๋ฃ๋๋ฉด, ๋ฐ์ดํฐ๋ stale ์ํ๊ฐ ๋๋ค.
- ํ์ง๋ง ๋ฐ๋ก refetch๋ ํ์ง ์๊ณ , ์๋ ์กฐ๊ฑด ์ค ํ๋๊ฐ ์ถฉ์กฑ๋ ๋ ๋ค์ ๊ฐ์ ธ์จ๋ค.
2. ์ปดํฌ๋ํธ๊ฐ ๋ค์ ๋ง์ดํธ๋ ๋ (refetchOnMount)
- stale ์ํ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๊ฐ ๋ค์ ๋ง์ดํธ๋๋ฉด ์๋์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค.
- ๊ธฐ๋ณธ๊ฐ: true → stale ์ํ๋ฉด ์๋์ผ๋ก refetch
useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
staleTime: 1000 * 60 * 5, // 5๋ถ ๋์ fresh ์ ์ง
refetchOnMount: true, // stale ์ํ๋ฉด ๋ง์ดํธ๋ ๋ ์๋ refetch
});
staleTime์ด ๋ง๋ฃ๋ ํ, ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ๋ค์ ๋ฐฉ๋ฌธํ๊ฑฐ๋, ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ ํ ์ฌ๋ง์ดํธ๋๋ฉด ์๋์ผ๋ก refetch.
3. ๋ธ๋ผ์ฐ์ ํฌ์ปค์ค๊ฐ ๋ค์ ํ์ฑํ๋ ๋ (refetchOnWindowFocus)
- ์ฌ์ฉ์๊ฐ ๋ค๋ฅธ ํญ์ ๋ณด๊ณ ์๋ค๊ฐ ํ์ฌ ํญ์ผ๋ก ๋์์ค๋ฉด ์๋์ผ๋ก refetch.
- ๊ธฐ๋ณธ๊ฐ: true → stale ์ํ์ผ ๋ ํฌ์ปค์ค ์ด๋ ์ refetch
useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
staleTime: 1000 * 60 * 5, // 5๋ถ ๋์ fresh ์ ์ง
refetchOnWindowFocus: true, // stale ์ํ์ผ ๋ ์ฐฝ ํฌ์ปค์ค ์ด๋ ์ ์๋ refetch
});
false๋ก ์ค์ ํ๋ฉด ํฌ์ปค์ค ์ด๋ํด๋ ์๋์ผ๋ก ๊ฐ์ ธ์ค์ง ์์.
4. ๋คํธ์ํฌ๊ฐ ๋ค์ ์ฐ๊ฒฐ๋ ๋ (refetchOnReconnect)
- ๋คํธ์ํฌ๊ฐ ๋๊ฒผ๋ค๊ฐ ๋ค์ ์ฐ๊ฒฐ๋๋ฉด ์๋์ผ๋ก refetch.
- ๊ธฐ๋ณธ๊ฐ: true
useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
refetchOnReconnect: true, // ๋คํธ์ํฌ ์ฌ์ฐ๊ฒฐ ์ ์๋ refetch
});
๋คํธ์ํฌ๊ฐ ๋์ด์ ธ ์๋ค๊ฐ ๋ค์ ์ฐ๊ฒฐ๋๋ฉด, stale ์ํ์ธ ์ฟผ๋ฆฌ๋ ์๋์ผ๋ก refetch.
5. ์ฌ์ฉ์ ์ก์ ์ผ๋ก ๊ฐ์ refetch (refetch() ๋๋ invalidateQueries())
- ๊ฐ๋ฐ์๊ฐ ๋ช ์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์ค๋๋ก ์์ฒญํ ์๋ ์๋ค.
const { data, refetch } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
staleTime: 1000 * 60 * 5, // 5๋ถ ๋์ fresh ์ ์ง
});
<button onClick={() => refetch()}>๋ฐ์ดํฐ ๋ค์ ๊ฐ์ ธ์ค๊ธฐ</button>
๋ฒํผ์ ๋๋ฅด๋ฉด ์ฆ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์ด.
queryClient.invalidateQueries({ queryKey: ["todos"] });
6. ํน์ ์๊ฐ๋ง๋ค ์๋์ผ๋ก refetch (refetchInterval)
- ์ผ์ ์ฃผ๊ธฐ๋ก ๋ฐ์ดํฐ๋ฅผ ์๋ก ๊ฐ์ ธ์ค๋๋ก ์ค์ ํ ์๋ ์๋ค.
useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
refetchInterval: 1000 * 60 * 5, // 5๋ถ๋ง๋ค ์๋ refetch
});
stale ์ํ์ ๊ด๊ณ์์ด ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ ๊ฐฑ์ ๊ฐ๋ฅ.
๋ฆฌํ์นญ์ ์ํ ๋ค์ํ ๋ฐฉ๋ฒ๋ค์ด ์์ง๋ง
์๋ ์์ํ๋ ๋ฐ์์ธ '๋ก๋ฉ ์ค...' ์ด ๋จ๊ฒ ํ๊ธฐ ์ํด gcTime์ ํ์ฉํด๋ณด์๋ค.
gcTime์ด ์ง๋๋ฉด ์บ์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
gcTime์ 0์ผ๋ก ์ฃผ์ด ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ ๋์๋ง์ ์บ์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ์ํจ๋ค.
staleTime์ด ๋ ๊ธธ์ง๋ง gcTime์ ์ํฅ์ ์ฃผ๋ ์ง ๊ถ๊ธํ๋ค.
// Detail.jsx
const { data, isLoading, error } = useQuery({
queryKey: ["todos", id],
queryFn: fetchDetail,
gcTime: 0,
staleTime: 1000 * 60,
});

- staleTime์ด ๋ ๊ธธ์ง๋ง ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ(Home์ผ๋ก ์ด๋) ๋์๋ง์ gcTime์ด ๋ฐํ๋จ
- Devtools์์ ํ์ธํ ์ ์๋ฏ์ด ์บ์ฑ๋ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ก ์ญ์ ๋จ
staleTime์ ๋ฐ์ดํฐ๊ฐ freshํ ์ํ์ ์๊ฐ์ ์ง์ ํ๋ฉฐ
gcTime์ ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ(์ธ๋ง์ดํธ) ๋์์ ๋๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ํ๋ค. (๊ธฐ๋ณธ 5๋ถ)
โจ staleTime ๊ณผ gcTime ์กฐํฉ
(๊ธฐ๋ณธ ์กฐ๊ฑด : staleTime๋ณด๋ค gcTime์ด ๋ ๊น)
const { data, isLoading, error } = useQuery({
queryKey: ["todos", id],
queryFn: fetchDetail,
gcTime: 1000 * 60 * 5,
staleTime: 1000 * 60,
});
๊ฒฝ์ฐ 1. data๋ fresh, ์บ์์ data๊ฐ ์์ ๋(staleTime๊ณผ gcTime ๋ชจ๋ ์ ์ง๋จ)
- staleTime ๋ด์ ํ <-> ๋ํ ์ผ์ ์ค๊ฐ๋ ์บ์๋ data๋ฅผ ํ์
- ๋ฐ์ดํฐ refetch ์ํจ (data๊ฐ stale ํ์ง ์์)
๊ฒฝ์ฐ 2. data๊ฐ stale, ์บ์์ data๊ฐ ์์ ๋(staleTime๋ง ์ง๋๊ณ gcTime์ ์ ์ง๋จ)
- ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ ๊น์ง ์บ์ฑ๋ data๋ฅผ ๋ณด์ฌ์ค
- ์์ ๋ค์ํ ๊ฒฝ์ฐ์ ๋ฐ๋ผ์ ๋ฆฌํ์นญ์ด ์งํ๋จ
๊ฒฝ์ฐ 3. staleTime๋ณด๋ค gcTime์ด ์งง์ ๋
- ์ปดํฌ๋ํธ๊ฐ ํ์ฑํ ๋์์ ๋๋ gcTime์ ๊ด๊ณ์์ด ์บ์ฑ๋ data๋ฅผ ํ์
- ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ ๋ ์ดํ๋ก gcTime์ด ์ ์ฉ ๋จ.
๊ฒฝ์ฐ 4. gcTime์ด ์ง๋ ์บ์ฑ๋ data๊ฐ ์ญ์ ๋ ๊ฒฝ์ฐ
- ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋๊น์ง(refetch ๋ ๋๊น์ง) ์ด๋ค ๋ฐ์ดํฐ๋ ๋ฐํํ์ง ์์
'Language > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [โ๏ธ] Tanstack Query(1) - useQuery, mutate, invalidateQueries (0) | 2025.03.08 |
|---|---|
| ์ฌ๊ธฐ์ state๋ฅผ ๊ตณ์ด? - ์ฌ๋ฆผํฝ ์ ๋ ฌ(sort) (0) | 2025.02.11 |
| [Pokemon PJ_Day 4] RTK (2) - ์ฌ์ฉํ๊ธฐ (0) | 2025.02.06 |
| [Pokemon PJ_Day 4] RTK (1) - ์ธํ ํ๊ธฐ (0) | 2025.02.06 |
| [โ๏ธ] Redux - counter ์ฑ ์์ฑ, redux ์ฌ์ดํด, dispatch (0) | 2025.02.03 |

