๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Frontend/TanStack Query

Queries

 

์ฟผ๋ฆฌ๋Š” ๊ณ ์œ ํ•œ ํ‚ค์— ์—ฐ๊ฒฐ๋œ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ๋Œ€ํ•œ ์„ ์–ธ์  ์˜์กด์„ฑ์ด๋‹ค. ์ฟผ๋ฆฌ๋Š” Promise๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋ชจ๋“  ์ข…๋ฅ˜์˜ ํ•จ์ˆ˜(GET, POST ๋ฉ”์„œ๋“œ ํฌํ•จ)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” Mutations๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

 

์ปดํฌ๋„ŒํŠธ๋‚˜ ์ปค์Šคํ…€ ํ›…์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, useQuery ํ›…์„ ์ตœ์†Œํ•œ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ธ์ž์™€ ํ•จ๊ป˜ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

  1. ์ฟผ๋ฆฌ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ ํ•œ ํ‚ค
  2. ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
    • ๋ฐ์ดํ„ฐ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์™€ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜
    • ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ด
import { useQuery } from '@tanstack/react-query'

function App() {
  const info = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
}

 

๊ณ ์œ  ํ‚ค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ฟผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๊ณ , ์บ์‹ฑํ•˜๋ฉฐ, ๊ณต์œ ํ•˜๋Š” ๋ฐ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. 

 

useQuery๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์—๋Š” ํ™”๋ฉด ํ…œํ”Œ๋ฆฟ ์ž‘์—…์ด๋‚˜ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })

 

result ๊ฐ์ฒด์—๋Š” ์ƒ์‚ฐ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์•Œ์•„๋‘ฌ์•ผ ํ•  ๋ช‡ ๊ฐ€์ง€ ๋งค์šฐ ์ค‘์š”ํ•œ ์ƒํƒœ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ์ฟผ๋ฆฌ๋Š” ํŠน์ • ์‹œ์ ์— ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ์ƒํƒœ๋งŒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

  • isPending ๋˜๋Š” status === 'pending': ์ฟผ๋ฆฌ์— ์•„์ง ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ์ดˆ๊ธฐ ๋กœ๋”ฉ ์ƒํƒœ
  • isError ๋˜๋Š” status === 'error': ์ฟผ๋ฆฌ ์‹คํ–‰ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์ƒํƒœ
  • isSuccess ๋˜๋Š” status === 'success': ์ฟผ๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ–ˆ์œผ๋ฉฐ data๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ

์ด๋Ÿฌํ•œ ์ฃผ์š” ์ƒํƒœ ์™ธ์—๋„ ์ฟผ๋ฆฌ ์ƒํƒœ์— ๋”ฐ๋ผ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

  • error: ์ฟผ๋ฆฌ๊ฐ€ isError ์ƒํƒœ์ผ ๋•Œ, error ์†์„ฑ์„ ํ†ตํ•ด ์—๋Ÿฌ ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • data: ์ฟผ๋ฆฌ๊ฐ€ isSuccess ์ƒํƒœ์ผ ๋•Œ, data ์†์„ฑ์„ ํ†ตํ•ด ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • isFetching: ์–ด๋–ค ์ƒํƒœ์—์„œ๋“  ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘์ผ ๋•Œ(๋ฐฑ๊ทธ๋ผ์šด๋“œ refetch ํฌํ•จ), isFetching ๊ฐ’์€ true๊ฐ€ ๋œ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ๋จผ์ € isPending ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ๊ทธ ๋‹ค์Œ isError ์ƒํƒœ๋ฅผ ํ™•์ธํ•œ ๋’ค, ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.

function Todos() {
  const { isPending, isError, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

  if (isPending) {
    return <span>Loading...</span>
  }

  if (isError) {
    return <span>Error: {error.message}</span>
  }

  // We can assume by this point that `isSuccess === true`
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

 

boolean ๊ฐ’ ๋Œ€์‹  ๋ฌธ์ž์—ด๋กœ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, status ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

function Todos() {
  const { status, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

  if (status === 'pending') {
    return <span>Loading...</span>
  }

  if (status === 'error') {
    return <span>Error: {error.message}</span>
  }

  // also status === 'success', but "else" logic works, too
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

 

TypeScript๋Š” pending๊ณผ error ์ƒํƒœ๋ฅผ ๋จผ์ € ํ™•์ธํ•˜๋ฉด, ๊ทธ ์ดํ›„ ์ฝ”๋“œ์—์„œ data์˜ ํƒ€์ž…์„ undefined๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์ถ”๋ก ํ•ด์ค€๋‹ค.

 

FetchStatus

 

status ํ•„๋“œ ์™ธ์—๋„, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ต์…˜์„ ๊ฐ€์ง„ fetchStatus ์†์„ฑ๋„ ์ œ๊ณต๋œ๋‹ค.

  • fetchStatus === 'fetching': ์ฟผ๋ฆฌ๊ฐ€ ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘์ด๋‹ค.
  • fetchStatus === 'paused': ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ–ˆ์ง€๋งŒ, ์ผ์‹œ ์ค‘์ง€๋˜์—ˆ๋‹ค.
  • fetchStatus === 'idle': ์ฟผ๋ฆฌ๊ฐ€ ํ˜„์žฌ ์•„๋ฌด ์ž‘์—…๋„ ํ•˜์ง€ ์•Š๋Š” ์œ ํœด ์ƒํƒœ์ด๋‹ค.

์™œ ๋‘ ๊ฐœ์˜ ๋‹ค๋ฅธ ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•œ๊ฐ€? (status, fetchStatus)

 

๋ฐฑ๊ทธ๋ผ์šด๋“œ refetch๋‚˜ stale-while-revalidate ๊ฐ™์€ ๋กœ์ง ๋•Œ๋ฌธ์— status์™€ fetchStatus์˜ ๋ชจ๋“  ์กฐํ•ฉ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

 

  • status๊ฐ€ success์ธ ์ฟผ๋ฆฌ๋Š” ๋ณดํ†ต fetchStatus๊ฐ€ idle์ด์ง€๋งŒ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ refetch๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด fetching์ด ๋  ์ˆ˜๋„ ์žˆ๋‹ค. (ํ™”๋ฉด์— ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋ฉด์„œ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์กฐ์šฉํžˆ ์ƒˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ƒํ™ฉ)
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋งˆ์šดํŠธ๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ์ฟผ๋ฆฌ๋Š” ๋ณดํ†ต status๊ฐ€ pending์ด๊ณ  fetchStatus๋Š” fetching์ด์ง€๋งŒ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์—†์œผ๋ฉด paused ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

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

  • status๋Š” ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•Œ๋ ค์ค€๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”๊ฐ€, ์—†๋Š”๊ฐ€?
  • fetchStatus๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜์ธ queryFn์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•Œ๋ ค์ค€๋‹ค. ์š”์ฒญ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰ ์ค‘์ธ๊ฐ€, ์•„๋‹Œ๊ฐ€?

 

https://tanstack.com/query/latest/docs/framework/react/guides/queries

 

Queries | TanStack Query React Docs

Query Basics A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise based method (including GET and POST methods) to f...

tanstack.com

 

'Frontend > TanStack Query' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Network Mode  (0) 2025.10.24
Query Options  (0) 2025.10.23
Query Functions  (0) 2025.10.22
Query Keys  (0) 2025.10.21
์™œ TanStack Query๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?  (0) 2025.10.19