๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
FE/React

Zustand vs TanStack Query, ๊ฐ™์ด ์“ฐ์ž!

by vellahw 2026. 3. 15.

 

๐Ÿป

์š”์ฆ˜ ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋กœ์ ํŠธ์—์„œ Zustand + TanStack Query๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฐ™์ด ๋“ฑ์žฅํ•œ๋‹ค.

์ฒ˜์Œ์—๋Š” ๋‘˜ ๋‹ค ์ƒํƒœ ๊ด€๋ฆฌ์ฒ˜๋Ÿผ ๋ณด์—ฌ์„œ ์ด๊ฑฐ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ ์“ฐ๋ฉด ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€? ์‹ถ์—ˆ๋Š”๋ฐ ์—ญํ• ์ด ์™„์ „ํžˆ ๋‹ค๋ฅด๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์‹ค์ œ ๋กœ๊ทธ์ธ ํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋А๋‚€ ์ฐจ์ด๋ฅผ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.


 

1. Zustand๋Š” ๋ฌด์—‡์ธ๊ฐ€?

Zustand๋Š” ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค.
Redux๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•˜๊ณ , ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋„ ๊ฑฐ์˜ ์—†๋‹ค.

ํ”„๋ก ํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณณ์œผ๋กœ,

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ ์—ด๋ฆผ ์—ฌ๋ถ€, ๋‹คํฌ๋ชจ๋“œ ์ƒํƒœ, ์‚ฌ์ด๋“œ๋ฐ” ์—ด๋ฆผ/๋‹ซํž˜, ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ํƒญ

์ด๋Ÿฐ ๊ฒƒ๋“ค์„ ์ €์žฅํ•œ๋‹ค.

 

์‚ฌ์šฉ์˜ˆ

import { create } from 'zustand'

export const useStore = create((set) => ({
  isOpen: false,
  toggle: () => set((state) => ({ isOpen: !state.isOpen })),
}))

 

 

2. TanStack Query๋Š” ๋ฌด์—‡์ธ๊ฐ€?

TanStack Query ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ์—”์ง„์ด๋‹ค.

์ฆ‰, API ํ˜ธ์ถœ์„ ์ค‘์‹ฌ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค.

๋‹จ์ˆœํžˆ fetch๋งŒ ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ

์บ์‹ฑ, ์ž๋™ ์žฌ์š”์ฒญ, ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ, ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” ๋“ฑ

์ด๋Ÿฐ๊ฑธ ์ „๋ถ€ ์•Œ์•„์„œ ํ•ด์ค€๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋Š” API๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด๋ณด์ž.

import { useQuery } from '@tanstack/react-query'
import axios from 'axios'

export const useAuthQuery = () => {
  return useQuery({
    queryKey: ['auth'],
    queryFn: async () => {
      const res = await axios.get('/api/auth/me', {
        withCredentials: true,
      })
      return res.data
    },
    retry: false,
  })
}

์ด ํ•œ ์ค„๋กœ “๋กœ๊ทธ์ธ ์ƒํƒœ + ์บ์‹ฑ + ๋กœ๋”ฉ + ์—๋Ÿฌ ์ฒ˜๋ฆฌ”๊ฐ€ ๋‹ค ํ•ด๊ฒฐ๋œ๋‹ค.

 

3. ๋‘˜์˜ ์ฐจ์ด ํ•œ ๋ฒˆ์— ์ •๋ฆฌ

๊ตฌ๋ถ„ Zustand TanStack Query
์—ญํ•  ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ์„œ๋ฒ„ ์ƒํƒœ
๋ฐ์ดํ„ฐ ์œ„์น˜ ๋ธŒ๋ผ์šฐ์ € ์„œ๋ฒ„
์ฃผ์š” ๊ธฐ๋Šฅ ์ƒํƒœ ์ €์žฅ API ๊ด€๋ฆฌ
๋กœ๋”ฉ/์—๋Ÿฌ ์ง์ ‘ ๊ตฌํ˜„ ์ž๋™ ์ œ๊ณต

ํ•ต์‹ฌ์€ “๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋””์—์„œ ์™”๋А๋ƒ”

๐ŸŸก ์„œ๋ฒ„์—์„œ ์™”๋‹ค → TanStack Query
๐ŸŸข ํ”„๋ก ํŠธ์—์„œ ๋งŒ๋“  ์ƒํƒœ๋‹ค → Zustand

 

 


 

 

4. ๋กœ๊ทธ์ธ ๊ตฌํ˜„์—์„œ์˜ ์‹ค์ œ ์ฐจ์ด

์นด์นด์˜ค ๋กœ๊ทธ์ธ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์ด ์ฐจ์ด๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์กŒ๋‹ค.

1. ๋กœ๊ทธ์ธ ์„ฑ๊ณต → accessToken, refreshToken ์ฟ ํ‚ค ์ €์žฅ
2. ํ”„๋ก ํŠธ๋Š” ํ† ํฐ์„ ์ฝ์„ ์ˆ˜ ์—†์Œ (httpOnly ์ฟ ํ‚ค)
3. API๋กœ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ํ™•์ธ

 

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํฌ์ธํŠธ, ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋Š” ์„œ๋ฒ„์— ๋ฌผ์–ด๋ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ

์ฆ‰, ์ด๊ฑด Zustand๊ฐ€ ์•„๋‹ˆ๋ผ TanStack Query ์˜์—ญ์ด๋‹ค.

 

๐ŸŒŸ ์˜ฌ๋ฐ”๋ฅธ ๊ตฌ์กฐ

์ฒ˜์Œ์—” Zustand์— ์œ ์ € ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฌธ์ œ๋Š” ํŽ˜์ด์ง€ ์ด๋™๋งˆ๋‹ค API๋ฅผ ํ˜ธ์ถœ ํ•ด์•ผํ•˜๊ณ , ๋™๊ธฐํ™”๊ฐ€ ๊นจ์ง€๋ฉฐ ์ƒํƒœ๊ฐ€ ๊ผฌ์ธ๋‹ค.

๊ทธ๋ž˜์„œ TanStack Query์—๋Š” ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ , Zustand์—๋Š” UI ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒŒ ๋งž๋‹ค!

 

1. TanStack Query → ์„œ๋ฒ„ ์ƒํƒœ

const { data, isLoading, isError } = useAuthQuery()
๐ŸŸก ๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ํŒ๋‹จ
๐ŸŸก ์œ ์ € ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
๐ŸŸก ์ž๋™ ์บ์‹ฑ

2. Zustand → UI ์ƒํƒœ

isLoginModalOpen: false
toggleLoginModal: () => {}
๐ŸŸข ๋ชจ๋‹ฌ ์—ด๋ฆผ ์—ฌ๋ถ€
๐ŸŸข UI ์ƒํƒœ ๊ด€๋ฆฌ

 

5. ์‹ค์ œ ํ๋ฆ„

์ตœ์ข…์ ์ธ ๋กœ๊ทธ์ธ ํ๋ฆ„:

๋ธŒ๋ผ์šฐ์ € ์ ‘์† (/)
→ ๋กœ๊ทธ์ธ ๊ฒ€์ฆ API ์š”์ฒญ
→ ์„œ๋ฒ„๊ฐ€ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ํŒ๋‹จ
→ TanStack Query๊ฐ€ ๊ฒฐ๊ณผ ๊ด€๋ฆฌ
→ ๋ผ์šฐํŒ… ๋ถ„๊ธฐ (/home ๋˜๋Š” /login)

์—ฌ๊ธฐ์„œ Zustand๋Š” ๋“ฑ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

๊ฒฐ๋ก 

์ฒ˜์Œ์—” ๋‘˜ ๋‹ค ์ƒํƒœ ๊ด€๋ฆฌ์ฒ˜๋Ÿผ ๋ณด์—ฌ์„œ ํ—ท๊ฐˆ๋ฆฌ์ง€๋งŒ
์‹ค์ œ๋กœ ์จ๋ณด๋ฉด ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋„๊ตฌ๋ผ๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋œ๋‹ค.

 

์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋Š” TanStack Query๋กœ ๊ด€๋ฆฌ
UI ์ƒํƒœ๋Š” Zustand๋กœ ๊ด€๋ฆฌ

 

์ด ๊ตฌ์กฐ๋กœ ๊ฐ€๋ฉด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋‹จ์ˆœํ•ด์ง€๊ณ ,
ํŠนํžˆ ๋กœ๊ทธ์ธ ๊ฐ™์€ ์ธ์ฆ ๋กœ์ง์ด ์•ˆ์ •์ ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.

 

 

 

๋Œ“๊ธ€