๐ค ์ '์ข์์' ๋ฒํผ์ ์ฆ์ ๋นจ๊ฐ์ ธ์ผ ํ ๊น์?
์ฌ๋ฌ๋ถ์ ์ธ์คํ๊ทธ๋จ์ด๋ ํ์ด์ค๋ถ์์ '์ข์์'๋ฅผ ๋๋ ์ ๋๋ฅผ
๊ธฐ์ตํ์๋์?
๋ฒํผ์ ๋๋ฅด๋ ์๊ฐ, ํํธ๋
์ฆ์ ๋นจ๊ฐ์์ผ๋ก ๋ณํฉ๋๋ค.
ํ์ง๋ง ์ค์ ๋ก๋ ๊ทธ ์์ฒญ์ด ์๋ฒ์ ๋๋ฌํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๊ธฐ๊น์ง
0.1์ด์์ ์ ์ด์ ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
๋ง์ฝ ์๋ฒ ์๋ต์ด ์ฌ ๋๊น์ง ๋ฒํผ์ด ๋ฐ์ํ์ง ์๋๋ค๋ฉด, ์ฌ์ฉ์๋ค์ ์ฑ์ด
๋ฉ์ท๋ค๊ณ ๋๋ ๊ฒ์
๋๋ค.
ํต์ฌ ๋ฌธ์ : ๋คํธ์ํฌ ์๋๋ ์ฐ๋ฆฌ๊ฐ ํต์ ํ ์ ์์ง๋ง,
์ฌ์ฉ์ ๊ฒฝํ(UX)์ ํต์ ํด์ผ ํฉ๋๋ค.
์๋ฒ ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋ฐ์ํ๋ '๋ฏธ์ธํ ๋ฉ์นซ๊ฑฐ๋ฆผ'์ด
์ฑ์ ์์ฑ๋๋ฅผ ๋จ์ด๋จ๋ฆฝ๋๋ค.
์ค๋ ์ฐ๋ฆฌ๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ React Query์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ,
'์ตํฐ๋ฏธ์คํฑ ์
๋ฐ์ดํธ(Optimistic Updates)'์ ๋ํด ๊น์ด
์์๋ณด๊ฒ ์ต๋๋ค.
์ด ๊ธฐ์ ์ ์ ์ฉํ๋ฉด ์ฌ๋ฌ๋ถ์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง์น ๋ก์ปฌ ์ฑ์ฒ๋ผ
๋น ๋ฆฟ๋น ๋ฆฟํ๊ฒ ๋๊ปด์ง ๊ฒ์
๋๋ค.
๐ก ์ตํฐ๋ฏธ์คํฑ ์ ๋ฐ์ดํธ๋ ๋ฌด์์ธ๊ฐ์?
์ด๋ฆ์์ ์ ์ ์๋ฏ์ด, '๋๊ด์ (Optimistic)'์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ
์์ธกํ๊ณ ์
๋ฐ์ดํธํ๋ ๋ฐฉ์์
๋๋ค.
์๋ฒ๋ก ์์ฒญ์ ๋ณด๋์ ๋, "์ฑ๊ณตํ ๊ฒ์ด๋ผ ๊ฐ์ ํ๊ณ " ๋ฏธ๋ฆฌ
ํ๋ฉด(UI)์ ๋ฐ๊ฟ๋ฒ๋ฆฌ๋ ์ ๋ต์ด์ฃ .
- ๐ธ ๊ธฐ์กด ๋ฐฉ์: ์์ฒญ ์ ์ก → ์๋ฒ ์ฒ๋ฆฌ ๋๊ธฐ (๋ก๋ฉ ์คํผ๋) → ์๋ต ๋์ฐฉ → UI ์ ๋ฐ์ดํธ
- ๐น ์ตํฐ๋ฏธ์คํฑ ๋ฐฉ์: ์์ฒญ ์ ์ก → ์ฆ์ UI ์ ๋ฐ์ดํธ → (๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋ฒ ์ฒ๋ฆฌ) → ์ฑ๊ณต ์ ์ ์ง / ์คํจ ์ ๋กค๋ฐฑ
์ด ๋ฐฉ์์ ์ฌ์ฉ์๊ฐ ๋๋ผ๋
์ฒด๊ฐ ์๋(Perceived Performance)๋ฅผ ํ๊ธฐ์ ์ผ๋ก
๋์ฌ์ค๋๋ค.
ํนํ ์ข์์, ์ฆ๊ฒจ์ฐพ๊ธฐ, ํ ์ผ ์ฒดํฌ ๋ฑ
์ํธ์์ฉ์ด ๋น๋ฒํ ๊ธฐ๋ฅ์์ ํ์์ ์
๋๋ค.
๐ ️ React Query์์์ ๋์ ์๋ฆฌ 3๋จ๊ณ
React Query(TanStack Query)๋ ์ด๋ฌํ ํจํด์ ๊ตฌํํ๊ธฐ ์ํด
useMutation ํ
๋ด๋ถ์ ์ ๊ตํ ๋ผ์ดํ์ฌ์ดํด ์ต์
์
์ ๊ณตํฉ๋๋ค.
ํฌ๊ฒ 3๊ฐ์ง ๋จ๊ณ๋ก ๋๋์ด ๋ณผ ์ ์์ต๋๋ค.
| ๋จ๊ณ (LifeCycle) | ์ญํ ๋ฐ ์ค๋ช |
|---|---|
| 1. onMutate |
์์ฒญ์ด ์์๋๋ ์ฆ์ ์คํ๋ฉ๋๋ค. ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ค๋ ์ท(๋ฐฑ์ ) ์ฐ๊ณ , UI๋ฅผ ์๋ก์ด ๊ฐ์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝํฉ๋๋ค. |
| 2. onError |
์๋ฒ ์์ฒญ์ด ์คํจํ์ ๋ ์คํ๋ฉ๋๋ค. onMutate์์ ์ ์ฅํด๋ ์ค๋ ์ท์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋กค๋ฐฑ(๋ณต๊ตฌ)ํ์ฌ ์ค๋ฅ ์๋ ์ํ๋ก ๋๋๋ฆฝ๋๋ค. |
| 3. onSettled |
์ฑ๊ณตํ๋ ์คํจํ๋ ์์ฒญ์ด ๋๋๋ฉด ์คํ๋ฉ๋๋ค. ์๋ฒ์ ์ต์ ๋ฐ์ดํฐ์ ๋๊ธฐํํ๊ธฐ ์ํด ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํ(invalidate)ํ์ฌ ์ฌ์์ฒญํฉ๋๋ค. |
๐ป ์ค์ ์ฝ๋๋ก ์ดํด๋ณด๊ธฐ
๋ฐฑ๋ฌธ์ด ๋ถ์ฌ์ผ๊ฒฌ์ด์ฃ ? 'ํ ์ผ ๋ชฉ๋ก(Todo)'์ ์๋ก์ด ํญ๋ชฉ์ ์ถ๊ฐํ๋ ์ํฉ์
๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค.
์๋ ์ฝ๋๋
์ฌ์ฉ์๊ฐ '์ถ๊ฐ' ๋ฒํผ์ ๋๋ฅด์๋ง์ ๋ชฉ๋ก์ ์ ํญ๋ชฉ์ด ๋ณด์ด๋ ๋ง๋ฒ์ ๊ตฌํํ ๊ฒ์
๋๋ค.
const mutation = useMutation({
mutationFn: newTodo => axios.post('/todos', newTodo),
// 1. ์์ฒญ ์ฆ์ ์คํ (๋๊ด์ ์
๋ฐ์ดํธ)
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey:
['todos'] });
const previousTodos =
queryClient.getQueryData(['todos']);
// UI๋ฅผ ๋ฏธ๋ฆฌ ์
๋ฐ์ดํธํฉ๋๋ค!
queryClient.setQueryData(['todos'], (old) =>
[...old, newTodo]);
return { previousTodos };
// ์ค๋
์ท ๋ฐํ
},
// 2. ์คํจ ์ ๋กค๋ฐฑ
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'],
context.previousTodos);
},
// 3. ์๋ฃ ํ ๋๊ธฐํ
onSettled: () => {
queryClient.invalidateQueries({ queryKey:
['todos'] });
}
});
์ด ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๋ ๋คํธ์ํฌ ์๋์ ๊ด๊ณ์์ด
์ฆ๊ฐ์ ์ธ ๋ฐ์์ ๊ฒฝํํ๊ฒ ๋ฉ๋๋ค.
์คํจํ ํ๋ฅ ์ด ๋ฎ์ ์์ฒญ์ ์ ์ฉํ ์๋ก ๊ทธ ํจ๊ณผ๋ ๋ฐฐ๊ฐ ๋ฉ๋๋ค.
๐ ์์ฝ ๋ฐ ์ค์ฒ ๊ฐ์ด๋
๐ ์ฅ์
- ์ฑ์ด ํจ์ฌ ๋น ๋ฅด๊ณ ๋ถ๋๋ฝ๊ฒ ๋๊ปด์ง.
- ์๋ฒ ์๋ต ๋๊ธฐ ์๊ฐ ๋์ ์ฌ์ฉ์๊ฐ ๋ค๋ฅธ ์์ ์ ํ ์ ์์.
- ๋ค์ดํฐ๋ธ ์ฑ ์์ค์ ๊ณ ํ์ง UX ์ ๊ณต.
⚠️ ์ฃผ์์ฌํญ
- ์คํจ ํ๋ฅ ์ด ๋์ ์์ฒญ(๊ฒฐ์ ๋ฑ)์๋ ์ฌ์ฉ ์์ .
- ๋กค๋ฐฑ ๋ก์ง(onError)์ ๊ผผ๊ผผํ๊ฒ ์์ฑํด์ผ ํจ.
- ๋ฐ์ดํฐ ์ ํฉ์ฑ์ด ๋งค์ฐ ์ค์ํ ๊ธฐ๋ฅ์๋ ์ ์คํ๊ฒ ์ ์ฉ.
React Query์ ์ตํฐ๋ฏธ์คํฑ ์
๋ฐ์ดํธ๋ ๋จ์ํ ๊ธฐ์ ์ ์ธ ๊ธฐ๊ต๊ฐ ์๋๋๋ค.
์ฌ์ฉ์์๊ฒ "๋น์ ์ ์์ฒญ์ ์ด๋ฏธ ์ฒ๋ฆฌ๋์์ต๋๋ค"๋ผ๋ ์ ๋ขฐ๋ฅผ
์ฃผ๋ UX ๋์์ธ์ ์ผ๋ถ์
๋๋ค.
์ค๋ ๋น์ฅ ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ ์๋ '์ข์์' ๋ฒํผ๋ถํฐ ์ด
๊ธฐ์ ์ ์ ์ฉํด๋ณด๋ ๊ฑด ์ด๋จ๊น์?
React Query ๊ณต์ ๋ฌธ์๋ฅผ ์ผ๊ณ , `useMutation` ํ ์ ์์ฑํด๋ณด์ธ์. ์์ ๋ณํ๊ฐ ํฐ ์ฐจ์ด๋ฅผ ๋ง๋ญ๋๋ค.



.png)
๋๊ธ ์ฐ๊ธฐ