๐ 19. ์ํ ๊ด๋ฆฌ์ ๊ถ๋ ฅ ๋ถ๋ฆฝ: ์๋ฒ(Server) ์ํ vs ํด๋ผ์ด์ธํธ(Client) ์ํ
๐ ๊ฐ์
Redux ํ๋๋ก ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ฑ์ฌ๋ฃ๋ ์๋๋ฅผ ์ง๋, ์ ํ๋ ํ๋ก ํธ์๋๋ ์๋ฒ ๋ฐ์ดํฐ(TanStack Query)์ UI ๋ฐ์ดํฐ(Zustand)๋ฅผ ์ฒ ์ ํ ๋ถ๋ฆฌํ๋์ง ์ํคํ ์ฒ ๊ด์ ์์ ํด๋ถํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ๊ณผ๊ฑฐ Redux-Thunk๋ Saga๋ก ๊ฒ์๊ธ ๋ชฉ๋ก์ ๋ถ๋ฌ์ค๊ณ ์บ์ฑํ๋(๋ณด์ผ๋ฌํ๋ ์ดํธ ์ง์ฅ) ์๋๊ฐ ์ ์ข ๋ง์ ๋ง์ดํ๋์ง ์ดํดํ๋ค.
- ์ํ(State)์ '์ฑ์ง'์ ํ์ ํ์ฌ, ๋ด ๋ฐ์ดํฐ๋ฅผ ์ด๋(Zustand vs TanStack Query)์ ๋ณด๊ดํด์ผ ํ ์ง 1์ด ๋ง์ ํ๋ณํ ์ ์๋ค.
- ๋ฐฑ์๋ DB์ ์บ์ ๋ณต์ฌ๋ณธ(์๋ฒ ์ํ)์ ํ๋ก ํธ์ ์์๊ฒ ๋๊ธฐํํ๋ ์บ์ฑ(Caching) ์ ๋ต์ ๊ธฐ์ด๋ฅผ ๋ค์ง๋ค.
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ: '์ ์ญ ์คํ ์ด ๋ง๋ฅ์ฃผ์'์ ํํด
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ๊ทน์ ์ฒด๋: ๋ ์์ข์ ๋ถ๋ฆฌ (Zustand & TanStack Query)
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 10๋ถ / ํต์ฌ ํํธ: 5๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์(PM): "์์ฒ ๋, ์ฐ๋ฆฌ ์ฑ์ ๊ฒ์๊ธ ๋ชฉ๋ก ์บ์ฑ๋ ํด์ผ ํ๊ณ , ๋คํฌ๋ชจ๋ ์ค์ ๋ ์ ์ญ์ผ๋ก ๊ธฐ์ตํด์ผ ํ๊ณ , ์ ์ ๊ฐ ์ด๋ค ๋ชจ๋ฌ์ฐฝ์ ๋์๋จ๋์ง๋ ๋ค ๊ธฐ์ตํด์ผ ํ๋๋ฐ ์ด๋ป๊ฒ ํฉ์ณ ๋์ผ์ จ๋์?"
- ์์ฒ (์ ์
): "๊ฑฑ์ ๋ง์ธ์! ๋ง๋ฅ ๋ณด๋ฐ๋ฆฌ
Redux Store๋ผ๋ ๊ฑฐ๋ํ ์คํ ์ด ํ๋ ํ ๋ค์์ ๊ฑฐ๊ธฐ์๋ค๊ฐ{ isDarkMode, isModalOpen, postsList, isLoading, errorMsg }์น ๋ค ๋๋ ค ๋ฐ์ ๋จ์ต๋๋ค! ์ก์ (Action) ์์ญ ๊ฐ๋ ๋ฆฌ๋์(Reducer) ์ง์ฅ๋ง ๊ฑฐ์น๋ฉด ๊บผ๋ด ์ธ ์ ์์ด์ ใ ใ " - ์ํธ(๋ฆฌ๋): "์์ฒ ๋, ๊ทธ๋์ ๋น์ ์ ์คํ ์ด ์ฝ๋๊ฐ 5,000์ค์ด ๋๋ ๊ฒ๋๋ค. ์ ๋ฐ์ดํฐ๋ค์ ํ์๋ถํฐ๊ฐ ๋ค๋ฅธ ๋จ๋จ์ ๋๋ค. ํด๋ผ์ด์ธํธ(UI) ์ํ์ ์๋ฒ(API) ์ํ๋ฅผ ํ ๋ฐ๊ตฌ๋์ ๋ด์ผ๋ฉด ๋ถํจํฉ๋๋ค. ์ค๋ ๋น์ฅ ๊ถ๋ ฅ ๋ถ๋ฆฝ์ ์์ํฉ์๋ค."
๐ค ์ ์์์ผ ํ๋๊ฐ: '์ ์ญ ์คํ ์ด ๋ง๋ฅ์ฃผ์'์ ํํด
2010๋ ๋ ํ๋ฐ ํ๋ก ํธ์๋๋ "๋ชจ๋ ์ค์ํ ๋ฐ์ดํฐ๋ ์ ์ญ(Global - Redux)์ผ๋ก ๋นผ์!"๋ผ๋ ์ฌ์์ ๋ฏธ์ณ์์์ต๋๋ค. ๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๊ดดํ ํํ์ ์คํ ์ด๊ฐ ํ์ํ์ต๋๋ค.
// โ 3๋
์ ํํ๋ ์์ฒ ์ด์ "์กํ๋ฐฅ ์ ์ญ ์ํ"
const globalRootStore = {
// ๐ข ํด๋ผ์ด์ธํธ(UI) ๊ณ ์ ์ํ - ์๋ก๊ณ ์นจํ๋ฉด ๋ ์๊ฐ๊ฑฐ๋ ๋ด ๊ธฐ๊ธฐ ๊ธฐ์ต์๋ง ์์กด
theme: 'dark',
isSidebarOpen: false,
cartFloatingXPosition: 150,
// ๐ด ์๋ฒ(Server) ์ํ์ ํ๋ก์ ๋ณต์ฌ๋ณธ - ๋จ(DB)์ ๋ฐ์ดํฐ๋ฅผ ํ์ณ์จ ๊ฒ
users: [{ id: 1, name: "์ํธ" }, { id: 2, name: "์์" }],
isUsersLoading: false,
usersError: null,
};์ด ์ฝ๋๋ ์ ๋์ฐํ ๊น์?
- **์บ์ฑ(Caching)**์ ํ๊ณ: ์์์ด๊ฐ ๋ณธ๋ช
๋๋ค์์ "์์_ํ๋ก"๋ก ๋ฐ๊ฟจ๋ค๊ณ ์นฉ์๋ค. ๋ด
users๋ฐฐ์ด ๊ฐ์ฒด(ํ๋ก ํธ ์ ์ญ ์คํ ์ด)๋ 10์๊ฐ ์ ์๋ฒ์์ ํ์ณ์จ "๋ก๊ณ ์ฉ์ ๊ณผ๊ฑฐ์ ๋ฐ์ดํฐ(Stale Data)"์ ๋๋ค. ์ด๊ฑธ ์ธ์ ๋ฌดํจํํ๊ณ ๋ค์ Fetch ํ ์ง, Redux์ ์์ ํจ์ ๋ฉ์ด๋ฆฌ ์์์ ์ง์ ๋ก์ง ๊ตฌํ์ ํ๋ ค๋ฉด ํผ๋ฅผ ํ ํฉ๋๋ค. - ์๋ ์ํ ๊ด๋ฆฌ(Boilerplate):
isUsersLoading,usersError๊ฐ์ ์ฐ๋ ๊ธฐ ํ๋๊ทธ ๊ฐ๋ค์ ์ก์ ๋ง๋ค ์๋์ผ๋ก ๊ป๋ค ์ผฐ๋ค(dispatchFETCH_START,FETCH_SUCCESS)ํด์ผ ํฉ๋๋ค. ์ก์ ํ์ ๋ช ์ง๋ค๊ฐ ๋ ์ ์๋๋ค.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
- ํด๋ผ์ด์ธํธ ์ํ(UI State): ๋ด ์๋์ ์๋ ์ผ๊ธฐ์ฅ์ด๋ ๊ฑฐ์ธ ๊ฐ๋์ ๋๋ค. **๋(Front-end ๋ธ๋ผ์ฐ์ )**๋ง์ ์์ ๊ถ๊ณผ ํต์ ๊ถ์ ์ฅ๊ณ ์์ต๋๋ค. ๋ด๊ฐ ๊ฐ๋๋ฅผ ํ๋ฉด ํ์ด์ง๊ณ , ๋คํฌ๋ชจ๋ ์ค์์น๋ฅผ ๋๋ฉด ๊บผ์ง๋๋ค. ๋ด ๋ง์๋๋ก ๋น ๋ฆฟ๋น ๋ฆฟํ๊ฒ ๋ค๋ฃฐ ์ ์์ต๋๋ค.
- ์๋ฒ ์ํ(Server State): ๋์๊ด์์ ์ด์ ๋น๋ ค์จ ๋ฐฑ๊ณผ์ฌ์ ์ ๋๋ค. ์๋ณธ ์์ ๊ถ์ ๋(ํ๋ก ํธ)์๊ฒ ์๊ณ **๋์๊ด(Backend DB)**์ด ์ฅ๊ณ ์์ต๋๋ค.
๋ด๊ฐ ๊ทธ ์ฑ ์ ์ง์ ๋ค๊ณ ์์ ์ฝ๋ ๋์, ๋์๊ด์ฅ์ด ์ฑ ์ ์๋ ๋ด์ฉ(์คํ)์ ์์ ํ๋ค๋ฉด? ๋ด ์ฑ ์ ์ฆ์ ๊ฑฐ์ง(Stale) ์ ๋ณด๊ฐ ๋์ด๋ฒ๋ฆฝ๋๋ค. ์ด๊ฑธ ๊ณ์ ๋์น์ฑ๊ณ ์ ๋ฒ์ ์ผ๋ก ๊ฐ์์น์ ์ค์ผ ํ๋ ์์ฒญ๋๊ฒ ํผ๊ณคํ ๊ด๋ฆฌ ๋์์ ๋๋ค.
์ด์ฒ๋ผ "๋ ํผ์๋ง์ ์ฐฐ๋์ ๊ธฐ์ต(UI)"๊ณผ "๋จ์ ๊ฑด๋ฌผ์์ ํ์ณ์จ ๋ก์ ๊ธฐ์ต(Server API)"์ ๋๊ฐ์ ์๋ ๋ฐ๊ตฌ๋(Zustand, Redux)์ ๋ฃ์ด ๊ณ ์ธ๋ฌผ๋ก ์ฉ๊ฒ ๋๋ ์ ์์ต๋๋ค. ๋ฐฉ์์ ์์ ํ ๋ถ๋ฆฌํด์ผ๋ง ํฉ๋๋ค.
๐งฉ ๊ทน์ ์ฒด๋: ๋ ์์ข์ ๋ถ๋ฆฌ (Zustand & TanStack Query)
์ต์ ์ค๋ฌด ํ(์คํํธ์ ~ํ ์ค, ๋น๊ทผ, ๋ฐฐ๋ฏผ ๋ฑ)์ ๋๋ถ๋ถ์ ์ ์ญ ์ํ๋ฅผ ์ํด ๋ฑ ๋ ๊ฐ์ง์ ๋ฌด๊ธฐ๋ง์ ๊บผ๋ด ๋ญ๋๋ค. ์์ฒ ์ด์ ๊ฑฐ๋ํ ์กํ ์คํ ์ด๊ฐ 2๊ฐ๋ก ์ฐข์ด์ง๋ ๊ธฐ์ ์ ๋ด ์๋ค.
โ 1. ์ค์ง "๋ด(Client)" ๋ฐ์ดํฐ๋ง ๊ด๋ฆฌํ๋ ์ด๊ฒฝ๋ ์คํ ์ด (Zustand)
๋คํฌ๋ชจ๋ ๋๊ณ ์ผ๊ธฐ, ํ์ฌ ์ผ์ ธ ์๋ ๋ชจ๋ฌ ID ์ ์ฅ, ๋๋๊ทธ ์ค ๋๋กญํ ๋ธ๋ก์ X,Y ์ขํ. ์ด๋ค์ ์๋ฒ๋ก ๋ ์๊ฐ ์ผ๋ ์๊ณ ์บ์ ๋ ํ์๋ ์๋ ์์ํ UI ํ๋ฐ์ฑ/ํด๋ผ์ด์ธํธ ์ํ์
๋๋ค.
๋จ ๋ช ์ค์ ์ฝ๋๋ก ์ ์ญ ๋ณ์๋ฅผ ์กฐ์ข
ํ ์ ์๋ Zustand๊ฐ ์ต๊ณ ์กด์์ผ๋ก ๋ฑ๊ทนํ์ต๋๋ค.
// ๐ฏ ์ค์ง ๋ธ๋ผ์ฐ์ UI ์กฐ์๋ง์ ๋ด๋ ๊น๋ํ Zustand
import { create } from 'zustand';
export const useUIStore = create((set) => ({
theme: 'dark',
toggleTheme: () => set((state) => ({ theme: state.theme === 'dark' ? 'light' : 'dark' })),
activeHoverId: null,
setHoverId: (id) => set({ activeHoverId: id }),
}));(์ด ๊ณต๊ฐ์ ์ ๋ ๋คํธ์ํฌ fetch ๊ฒฐ๊ณผ๋ฌผ์ ๋ฃ์ง ์์ต๋๋ค!)
โ 2. ๊ณจ์น ์ํ "๋จ(Server)"์ ๋ฐ์ดํฐ ์บ์ฑ ๋งค๋์ (TanStack Query)
"์๋ฒ์ผ ๋ ์ข ์ค"๋ผ๊ณ ์์ฒญํ๋ ์๊ฐ ๋ฒ์ด์ง๋ ๋ก๋ฉ ์ฒ๋ฆฌ, ์คํจ ์ 3๋ฒ ์๋ ์ฌ์์ฒญ(Retry), ์ ์ ๊ฐ ์ฐฝ์ ๋ด๋ ธ๋ค๊ฐ 3๋ถ ๋ค ์ผฐ์ ๋ (Focus) ๋ค์์ ๋ชฐ๋ ์ ๋ฐ์ดํฐ ๊ฐฑ์ ํ๊ธฐ(Stale-While-Revalidate)...
์ด ๋์ฐํ ์ก๋ฌด๋ค์ ์์์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์บ์ฑ ์ ๊ตญ์ ๊ฑด์คํ์ฌ ๋ค์ด๋ ํธ๋ก ๊ด๋ฆฌํด ์ฃผ๋ ๊ฒ์ด **React Query(TanStack Query)**์
๋๋ค. 16๊ฐ์ Suspense์๋ ์ํผ์ ๋จ์ง์
๋๋ค.
// ๐ฏ ์๋ฒ ์ํ: ํ๋ก ํธ๋ ๊ทธ์ Query Key๋ก ๊ตฌ๋
(Subscribe)๋ง ํ๊ณ ๊ฟ์ ๋นค๋ค.
import { useQuery } from '@tanstack/react-query';
function UserProfile({ userId }) {
// Redux์ Dispatch, useSelector ๊ทธ๋ด ๊ฑด ์์ผ์ธ์.
// ์ด ํ
ํ๋๊ฐ "์บ์ฑ, ๋ก๋ฉ, ์๋ฌ, ์ฌ๊ฐฑ์ , ๋ฉ๋ชจ๋ฆฌ ํ๊ธฐ"๋ฅผ ์น ํผ์ ๊ด๋ฆฌํด๋ฒ๋ฆผ.
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId], // ๋ง์น ์บ์ ์ฐฝ๊ณ ์ ๋ฐ์ฝ๋(์ด๋ฆํ) ๊ฐ์ ๊ฒ!
queryFn: () => fetch(`/api/users/${userId}`).then(res => res.json()),
staleTime: 1000 * 60 * 5, // "5๋ถ ๋์์ ๋์๊ด์ ๋ ์ ๋ฌผ์ด๋ณด๊ณ , ๋ด ์บ์ ๋ณต์ฌ๋ณธ ์ธ๊ฒ!"
});
if (isLoading) return <Spinner />;
if (error) return <div>์๋ฌ๋จ!</div>;
return <div>{user.name} ๋ ํ์!</div>;
}์ด๋ ๊ฒ ํ๋ฉด ๋ธ๋ผ์ฐ์ ๋ "์๋ฒ ๋ฐ์ดํฐ๋ฅผ ๋ณด๊ดํ๊ธฐ ์ํ ์ํ ๊ด๋ฆฌ ๋๊ตฌ"๋ผ๋ ๋ง๋ น์์ ์์ ํ ํด๋ฐฉ๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ํ๋ก ํธ์๋์์ ๋ฐ๋ผ๋ณด๋ ์๋ฒ ๋ฐ์ดํฐ๋, ์ํ(State)๋ก ๋ค๋ฃจ๋ ๊ฒ์ด ์๋๋ผ ๊ทธ๋ฅ Query์๊ฒ"์บ์ ๋ฐ์ดํฐ ์ต์ ๋ฒ์ ๋ณต์ฌ๋ณธ ์ข ๋์ ๊บผ๋ด์ ์ ์ ๋ณด์ฌ์ค"ํ๊ณ ๋น๋ ค ์ฐ๋ ๋ ๋๋ง ์ค๋ ์ท์ ๋ถ๊ณผํ๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
| ๊ด์ | UI ์ํ (ํด๋ผ์ด์ธํธ ์ํ) | API ์๋ฒ ์ํ (Server State) |
|---|---|---|
| ์์ ๊ถ (Truth) | ํ๋ก ํธ์๋(Client/Browser) | ๋ฒก์๋(DB) |
| ํน์ง | ์ฆ๊ฐ์ , ๋๊ธฐ์ , ์ผ์์ (ํ๋ฉด ๋ซ์ผ๋ฉด ํ ๋ ์๊ฐ) | ๋น๋๊ธฐ์ , ์ธ์ ๋ ์ง ๊ตฌํ ๋ฐ์ดํฐ(Stale)๋ก ์ฉ์ด๋ฒ๋ฆด ์ํ ์กด์ฌ |
| ์ ํฉํ ๋ฐ์ดํฐ ์์ | ๋ชจ๋ฌ ์ด๋ฆผ ์ฌ๋ถ, ๋คํฌ ๋ชจ๋, ์ธํ ์ ๋ ฅ๊ฐ | ๊ฒ์ํ ๊ธ ๋ชฉ๋ก, ๋ด ํ๋กํ ์ค์ , JWT ๊ถํ ์ ๋ณด |
| ๋ํ์ ์ธ ์ค๋ฌด ํด | Zustand, Jotai, Recoil, Redux(๋ฌด๊ฑฐ์) | TanStack Query (๊ตฌ React Query), SWR |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
"๋ด ๋ฐ์ดํฐ๋ Zustand์ ์จ๊ธฐ๊ณ , ๋จ(์๋ฒ)์ ๋ฐ์ดํฐ๋ Query์๊ฒ ์ธ์ฃผ(Outsourcing) ์ค๋ฒ๋ ค๋ผ."
์ด ๊ฑฐ๋ํ ๋ ์ถ๋ง ๋ช ํํ ๊ฐ๋ผ๋ด๋, ๋น์ ์ ํ๋ก ํธ์๋ ์ค๊ณ ์ํคํ ์ฒ๋ ํ ์ค๋ ์นด์นด์ค๊ธ ์๋์ด์ ์์ผ๋ฅผ ๊ฐ์ถ ๊ฒ๊ณผ ๋ค๋ฆ์๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
Redux ํ๋์ ๋ชจ๋ ์ธ์์ ์ง์ ๋ค ์ง์ด์ง๊ฒ ํ๋ ๋ด ์ฝ๋๊ฐ ์ผ๋ง๋ ๋ฏธ๋ จํ๋์ง ๊นจ๋ฌ์๋ค. ํด๋ผ์ด์ธํธ ๋ฐ์ดํฐ๋ ์๋ฒ ๋ฐ์ดํฐ๊ฐ ์ ์ด์ ์ ํจ๊ธฐ๊ฐ๋ถํฐ ๋ค๋ฅธ ๋จ๋จ์ด์๋ค๋.
๐ก "๋ช ์ฌํ์. ๋ด ์ฑ์ ์์ UI ์ํ(Zustand)์ ์๋ฒ์์ ๋น๋ ค์จ ์ฅ๋ถ ๋ณต์ฌ๋ณธ(TanStack Query)์ ์์ ํ ๋ถ๋ฆฌํด์ ๊ด๋ฆฌํด์ผ ํ๋ค."
์ด '๊ถ๋ ฅ ๋ถ๋ฆฝ' ํจํด๋๋ก๋ฉด ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋ ์๋ฐฑ ์ค์ด ๊ทธ๋ฅ ๋ ์๊ฐ๋ค. ๋น์ฅ ๋ด์ผ ์ถ๊ทผํด์ ๊ทธ ๋ฌด๊ฒ๊ณ ๋๋ฆฐ Redux ๊ฑท์ด๋ด๊ณ Zustand๋ React Query ๋์ ํ์๊ณ ๊ธฐ์์๋ถํฐ ์ฌ๋ ค์ผ๊ฒ ๋ค. ํ ์ค๋ ๋น๊ทผ์์ ์ ์ด ์กฐํฉ์ ์ฐ๋์ง ์ ๊ฒ ๊ฐ์ ์์ด ๋ปฅ ๋ซ๋ฆฐ๋ค.
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๋น์ ์ด ์ผํ๋ชฐ ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง๋ฅผ ์ค๊ณํด์ผ ํฉ๋๋ค. ๊ฐ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ ์ ์๋์ '์ฆ๊ฐ(+)/๊ฐ์(-)'์ํค๋ ๋ฒํผ์ ๋๋ ์ ๋ ๋ฒ์ด์ง๋ ์ผ์ ์ค๊ณํ ๊ฒ์ ๋๋ค. "UI ์ํ"์ "์๋ฒ ์ํ"์ ๋ถ๋ฆฌ ์์น์ ๋น์ถ์ด ๋ณผ ๋, ๊ฐ์ฅ ์ฌ๋ฐ๋ฅธ ๋ฉํ ๋ชจ๋ธ์ด๋ ํ๋ ๋ฐฉ์์ ๋ฌด์์ธ๊ฐ์?
- A) [+] ๋ฒํผ์ ๋๋ฅธ ์ฆ์ Zustand ์ํ ๋ณ์๋ก
cartItems[0].quantity + 1์ ๋๋ ค ๋ฐ์ ์ ์ญ ์ํ๋ฅผ ์ค์ผ์ํค๊ณ , ๊ตณ์ด DB ์๋ฒ๋ก ์ฌ์ ์กํ์ง ์์ ์ฑ ์ ์ ๊ฐ ๊ฒฐ์ ์ฐฝ์ผ๋ก ๋์ด๊ฐ ๋๋ง API๋ฅผ ํธ์ถํ๋ค. - B) [+] ๋ฒํผ์ ๋๋ฅด๋ฉด ์ด๊ฑด ๋ช
๋ฐฑํ ๋ฐฑ์๋ ์ฅ๋ฐ๊ตฌ๋ DB ํ
์ด๋ธ(Server State)์ ์์ ํด์ผ ํ๋ ์ง์์ด๋ฏ๋ก, TanStack Query์
Mutation๊ธฐ๋ฅ ๋ฑ์ ํ์ฉํด ์๋ฒ๋ก ๋ช ๋ น์ ๋ ๋ฆฐ๋ค. ์ฑ๊ณต ์๋ต์ด ๋จ์ด์ง๋ฉด, ์ฝํ์๋ ํด๋น '์ฅ๋ฐ๊ตฌ๋ ์ฟผ๋ฆฌ ๋ฌดํจํ(Invalidation)'๋ฅผ ๋๋ ค์ ์๋ฒ์ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์ค๋ฌผ์ค๋ฌผ ๋ฐ์์ ํ๋ฉด์ ์ ์ซ์๋ฅผ ๋ ๋๋งํ๋ค. - C) ์ด ์ํ๋ ํด๋ผ์ด์ธํธ์ ํต์ ๋ฅผ ๋ฐ๋ฅด๋ฏ๋ก LocalStorage์ ์ ์ฅํ์ฌ ์บ์ ๋งค๋์ ๋์ ๋ธ๋ผ์ฐ์ ์์ง์ ์จ์ ํ ์์ํด์ผ ํ๋ค.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ํ๋ฅญํ ๊ถ๋ ฅ ๋ถ๋ฆฝ ์ค๊ณ์
๋๋ค. ์ฅ๋ฐ๊ตฌ๋ ์๋์ ๊ฒฐ๊ตญ ์ ์ ์ ์ง๊ฐ(๊ฒฐ์ )๊ณผ ์ฐ๊ฒฐ๋ "๋จ์ ํต์ (์๋ฒ ์ฅ๋ถ)" ๋ฐ์ดํฐ์ด๋ฏ๋ก, ๋ด๊ฐ ๋ก์ปฌ ์ํ(UI)๋ก ํจ๋ถ๋ก ์ฆ์ ์์ ํ์ฌ ๋ต๋ต๊ฑฐ๋ฆฌ๋ฉด ์ ๋ฉ๋๋ค. ๋ฌด์กฐ๊ฑด ์๋ฒ์๊ฒ "ํ๋ ๋ ๋๋ ค์ฃผ์ธ์"๋ผ๊ณ ํ๋ฝ(mutate)์ ๊ตฌํ๊ณ , ์๋ณธ ์ฅ๋ถ(DB)๊ฐ ์์ ๋ ํ ๊ทธ ์ต์ ๋ฐ์ดํฐ(Query)๋ฅผ ์๋ก๊ณ ์นจ(Invalidate)์์ผ ํ๋ฉด์ ๋ฐ์ํ๋ ํ๋ฆ์ด ์์ ํ ๋๊ธฐํ์ ๊ธฐ๋ณธ์
๋๋ค. (๋ฌผ๋ก Optimistic Update๋ผ๋ ๊ธฐ๋ฒ๋ ์์ง๋ง, ์ด๋
์ ๋ณธ์ง์ ์ผ๋งฅ์ํตํฉ๋๋ค.)
Q2. ์ ์
์ธ ์์ฒ ์ด๊ฐ Context API์ ๋ด์ฅ ๊ธฐ๋ฅ๋ง์ผ๋ก ์ผํ๋ชฐ ์ ์ฒด์ ์ํ ๋ชฉ๋ก(10๋ง ๊ฐ ๋ฐ์ดํฐ)์ ๋ก๋ฉ/์บ์ฑ/๊ธฐ์ตํ๋ ์์คํ
์ ๊ฐ๋ฐํด ์์ต๋๋ค. ์ํธ ์๋์ด๊ฐ ์ด๋ฅผ ๋ณด๊ณ ํธํต์น๋ฉฐ TanStack Query๋ก ๋ฐ๊พธ๋ผ๊ณ ํ ์น๋ช
์ ์ธ ๋จ์ ๋ค์ ๋ชจ๋ ๋์ดํ๊ณ , Query๋๊ตฌ๋ค์ด ์ด๋ฐ ๋ฌธ์ ๋ฉ์ด๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํด์ฃผ๋์ง ์ง์ ์ฃผ๊ด์์ผ๋ก ์ค๋ช
ํด๋ณด์ธ์.
โ
์ ๋ต ๋ฐ ์ฃผ๊ด์ ํด์ค:
"์์ฒ ์ด ๋ฐฉ์์ ์น๋ช
์ ์ธ ๋จ์ ์, Context API์ ๋ด๋ ค๋ฐ์ 10๋ง ๊ฐ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ์๊ฐ์ด ์ง๋๋ฉด '์ ์ ๋'๋ฅผ ์์ด๋ฒ๋ฆฌ๋ ์ผํ์ฑ ๋ฐ๊ตฌ๋์ ๋ถ๊ณผํ๋ค๋ ์ ์
๋๋ค. ๋ค๋ฅธ ์ ์ ๊ฐ ์ฌ๊ณ ๋ฅผ ๋ค ์ฌ๊ฐ์ 0๊ฐ๊ฐ ๋์๋๋ฐ, ์์ฒ ์ด์ ์บ์(Context state)๋ 100๊ฐ๊ฐ ๋จ์๋ค๊ณ **๊ฑฐ์ง๋ง(Stale)**์ ์น ๊ฒ์
๋๋ค.
์ด๊ฑธ ํด๊ฒฐํ๋ ค๋ฉด ์์ฒ ์ด๊ฐ ์ง์ setTimeOut์ด๋ ์คํฌ๋กค ๋ฐฑ๊ทธ๋ผ์ด๋ ์ด๋ฒคํธ ๋ก์ง ๋ฑ์ ๋ชจ์กฐ๋ฆฌ ์๋ฐฑ ์ค ์์ผ๋ก ์ง์ผ ํ์ฃ . TanStack Query๋ ๋จ์ง staleTime: 5000 ํ ์ค ์ต์
๋ง ๋๊ฒจ์ฃผ๋ฉด, ํฌ์ปค์ค๊ฐ ๋์์์ ๋๋, 5์ด๊ฐ ์ง๋ฌ์ ๋ ์๊ธฐ ํผ์์ ์์์ ๋ค์์ ๋ชฐ๋ ํต์ ํ๊ณ (Background Fetching) ์ฉ์ ๋ถ๋ถ์ ์ต์ ํ๋ ์๋ฒ ๋ฐ์ดํฐ๋ก ์๋ฒฝํ๊ฒ ๋ฒ๋ฌด๋ ค ์บ์ฑ(Caching)๊น์ง ๋ํํด์ฃผ๋ ์ ์ธ์ ๊ฐฑ์ (Revalidate)์ ์
๋ง์ด๊ธฐ ๋๋ฌธ์
๋๋ค."