Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

탄탄대로

[vue-query] 개요 본문

FrontEnd/Vue.js

[vue-query] 개요

nvvs 2024. 6. 19. 09:54

vue-query 란?

vue-query는 애플리케이션에서 서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 보다 쉽게 다룰 수 있도록 도와주는 라이브러리입니다. 클라이언트 상태와 서버 상태를 명확히 구분하기 위해 만들어졌습니다.

기존 상태 관리 라이브러리(vuex, pinia 등)는 클라이언트 상태 작업에 적합하지만, 비동기 또는 서버 상태 작업에는 그다지 좋지 않습니다.

클라이언트 상태(Client State)와 서버 상태(Server State)는 완전히 다른 개념이기 때문입니다.

  • 클라이언트 상태는 각각의 input 값으로 예를 들 수 있고,
  • 서버 상태는 데이터베이스에 저장되어 있는 데이터로 예를 들 수 있습니다.

vue-query의 배경

TanStack

High-quality open-source software for web developers. Headless, type-safe, & powerful utilities for State Management, Routing, Data Visualization, Charts, Tables, and more.

웹 개발자를 위한 고품질 오픈 소스 소프트웨어입니다. 상태 관리, 라우팅, 데이터 시각화, 차트, 테이블 등에 대한 헤들리스(headless), 타입 안전(type-safe), 강력한 유틸리티를 제공합니다.

React Query는 v4부터 TanStack Query로 라이브러리 명이 변경되었습니다.

React 전용의 서버 상태 관리 라이브러리로 쓰이던 것이 v4부터는 Vue, Angular, Solid등 다른 프레임워크를 지원하기 시작했습니다.

이제는 TanStack Query 하위에 react-query, vue-query 등이 존재하는 형식이 되었습니다.

vue-query는 react-query에 기반을 두고 있다는 것이 이러한 배경 때문입니다.

 

vue-query를 사용하는 이유

대부분의 전통적인 상태 관리 라이브러리는 클라이언트 상태 처리에 탁월하지만, 비동기적 또는 서버 상태 처리에는 그다지 적합하지 않습니다.

Vue Query 패키지는 Vue에서 비동기 데이터를 가져오고 캐싱하고 업데이트하기 위한 후크를 제공합니다.

서버 상태 관리를 위해 vue-query를 사용합니다.

vue-query는 애플리케이션 내에서 아래와 같은 항목을 효과적으로 관리할 수 있는 기능을 제공합니다.

  • 캐싱 (프로그래밍에서 가장 어려운 일 중 하나일 수 있음)
  • 동일한 데이터에 대한 여러 요청을 단일 요청으로 중복 제거
  • 백그라운드에서 오래된 데이터 업데이트
  • 데이터가 오래되었는지 확인하기
  • 데이터 업데이트를 가능한 빨리 반영하기
  • 페이지네이션 및 데이터의 지연 로딩과 같은 성능 최적화
  • 서버 상태의 메모리 및 가비지 컬렉션 관리
  • 구조 공유를 통한 쿼리 결과의 메모화

vue-query를 사용하므로써 기대되는 측면은 아래와 같습니다.

  • 코드 단순화
    • 응용 프로그램에서 복잡하고 오해를 받는 코드를 제거하고 Vue Query 로직의 소수 라인으로 대체하는 데 도움이 될 것입니다.
  • 유지 관리의 간편화
    • 새로운 서버 상태 데이터 원본을 연결하는 데 걱정하지 않고 응용 프로그램을 유지 관리하기 쉽고 새로운 기능을 쉽게 구축할 수 있게 해줄 것입니다.
  • 빠른 반응성
    • 사용자가 애플리케이션을 이전보다 더 빠르고 반응성 있게 느끼도록 도와줄 것입니다.
  • 메모리 절약
    • 대역폭을 절약하고 메모리 성능을 향상시키는 데 도움이 될 수 있습니다.

 


vue-query 기본 사항

캐싱 라이프 사이클

  1. A라는 queryKey를 가진 A 쿼리 인스턴스가 mount됩니다.
  2. 네트워크에서 데이터 fetch하고, 불러온 데이터는 A라는 queryKey로 캐싱합니다.
  3. 이 데이터는 fresh상태에서 staleTime(기본값 0) 이후 stale 상태로 변경됩니다.
  4. A 쿼리 인스턴스가 unmount됩니다.
  5. 캐시는 gcTime(기본값 5min) 만큼 유지되다가 가비지 콜렉터(GC)로 수집됩니다.
  6. 만일, gcTime 지나기 전이고, A 쿼리 인스턴스 fresh한 상태라면 새롭게 mount되면 캐시 데이터를 보여줍니다.
  • 기본적으로 gcTime이 5분이고 staleTime이 0으로 가정합니다.
  •  Time
    • gcTime: 데이터를 사용하지 않거나, inactive 상태일때 캐싱 된 상태로 남아있는 시간 (밀리초)
    • staleTime: 데이터가 fresh에서 stale 상태로 변경되는 데 걸리는 시간
  • State
    • fresh: 뜻 그대로 ‘신선한’이라는 의미. 최신 상태라는 의미
    • stale: 뜻 그대로 ‘썩은’이라는 의미. 최신 상태가 아니라는 의미

백그라운드에서 데이터를 다시 가져오는 조건

  • 쿼리의 새로운 인스턴스가 마운트될 때
  • 창이 다시 초점을 맞출 때
  • 네트워크가 다시 연결될 때
  • 쿼리가 선택적으로 다시 가져오기 간격으로 구성될 때

 


vue-query의 세 가지 핵심 개념

vue-query의 세 가지 핵심 개념은 아래와 같습니다.

  • Queries
  • Mutations
  • Query Invalidation

Queries

A query is a declarative dependency on an asynchronous source of data that is tied to a unique key

쿼리는 고유한 키에 연결된 비동기 데이터 소스에 대한 선언적 종속성입니다.

쿼리는 서버에서 데이터를 가져오기 위해 Promise와 함께 사용합니다.

컴포넌트나 사용자 정의 훅에서 쿼리를 사용하려면 useQuery를 사용합니다.

 

useQuery

기본적으로 서버에서 데이터를 GET 할 때 사용합니다.

useQuery는 v5부터 인자로 단 하나의 객체만 받습니다. 그중에 queryKey, queryFn은 필수 값입니다.

const result = useQuery({
  queryKey: ['todos'], // key 배열 [필수]
  queryFn: fetchTodoList, // 쿼리에서 작동시킬 함수 [필수]
  // options ...
})

 

querykey

기본적으로 TanStack Query는 쿼리 키를 기반으로 쿼리 캐싱을 관리합니다.

쿼리 키는 최상위 수준에서 배열이어야 하며, 단일 문자열을 포함하는 간단한 배열부터 여러 문자열과 중첩된 객체로 구성된 복잡한 배열까지 가능합니다. 쿼리 키가 직렬화 가능하고 쿼리 데이터에 고유하다면 사용할 수 있습니다.

 

  • 단일 문자열을 포함하는 간단한 배열
    • 가장 간단한 형태의 키로 상수 값으로 구성된 배열.
// A list of todos 
useQuery({ queryKey: ['todos'], ... }) 

// Something else, whatever! 
useQuery({ queryKey: ['something', 'special'], ... })

 

  • 여러 문자열과 중첩된 객체로 구성된 복잡한 배열
    • 쿼리에 더 많은 정보가 필요할 때, 문자열과 직렬화 가능한 객체를 포함하는 배열을 사용.
    • 해당 배열을 통해 쿼리에 매개변수가 전달.
// An individual todo
useQuery({ queryKey: ['todo', 5], ... })

// An individual todo in a "preview" format
useQuery({ queryKey: ['todo', 5, { preview: true }], ...})

// A list of todos that are "done"
useQuery({ queryKey: ['todos', { type: 'done' }], ... })

 

쿼리 키는 결정론적으로 해시

  • 객체 내 키의 순서와 상관없이, 다음과 같은 모든 쿼리가 동일하게 간주된다는 것을 의미.
useQuery({ queryKey: ['todos', { status, page }], ... })
useQuery({ queryKey: ['todos', { page, status }], ...})
useQuery({ queryKey: ['todos', { page, status, other: undefined }], ... })
  • 만일 배열 항목의 순서가 다를 경우 다른 쿼리 키로 간주. 배열 항목의 순서가 중요.
useQuery({ queryKey: ['todos', status, page], ... })
useQuery({ queryKey: ['todos', page, status], ...})
useQuery({ queryKey: ['todos', undefined, page, status], ...})

 

쿼리 함수가 변수에 의존하는 경우, 해당 변수를 쿼리 키에 포함시켜야 합니다.

  • 쿼리 함수 내에서 사용되는 모든 변수는 쿼리 키에 추가되어야 합니다.
  • 이렇게 함으로써 쿼리가 독립적으로 캐시되고 변수가 변경될 때 자동으로 쿼리가 다시 가져와집니다.
/* 틀린 선언 */

useQuery({
  queryKey: ['todo'],
  queryFn: () => api.getTodo(todoId),
})

const todoQueries = {
  detail: (id) => ({ queryKey: ['todo'], queryFn: () => api.getTodo(id) }),
}
/* 맞은 선언 */

useQuery({
  queryKey: ['todo', todoId],
  queryFn: () => api.getTodo(todoId),
})

const todoQueries = {
  detail: (id) => ({ queryKey: ['todo', id], queryFn: () => api.getTodo(id) }),
}

 

queryFn

쿼리 함수는 Promise을 반환하는 어떤 함수든지 될 수 있습니다.

useQuery({ queryKey: ['todos'], queryFn: fetchAllTodos })

useQuery({ queryKey: ['todos', todoId], queryFn: () => fetchTodoById(todoId) })

useQuery({
  queryKey: ['todos', todoId],
  queryFn: async () => {
    const data = await fetchTodoById(todoId)
    return data
  },
})

 

각 쿼리 함수에는 QueryFunctionContext 객체가 전달됩니다.

쿼리 키는 QueryFunctionContext 객체에서 제공하는 항목 중 하나로, 항상 필요한 것은 아니지만 필요한 경우 쿼리 함수에서 쿼리 키를 추출할 수 있습니다.

useQuery({
  queryKey: ['todos', todoId],
  queryFn: ({ queryKey }) => fetchTodoById(queryKey[1]),
})
const result = useQuery({
  queryKey: ['todos', { status, page }],
  queryFn: fetchTodoList,
})

// Access the key, status and page variables in your query function!
function fetchTodoList({ queryKey }) {
  const [_key, { status, page }] = queryKey
  return new Promise()
}

 

QueryFunctionContext

QueryFunctionContext는 각 쿼리 함수에 전달되는 객체입니다.
다음과 같은 구성 요소로 이루어져 있습니다

  • queryKey: QueryKey: 쿼리 키
  • signal?: AbortSignal
    • TanStack Query에서 제공하는 AbortSignal 인스턴스
    • 쿼리 취소에 사용될 수 있습니다.
  • meta: Record<string, unknown> | undefined
    • 쿼리에 대한 추가 정보를 채울 수 있는 선택적 필드입니다.

또한, Infinite Queries에는 다음 옵션이 전달됩니다

  • pageParam: TPageParam
    • 현재 페이지를 가져오는 데 사용되는 페이지 매개변수
  • direction: 'forward' | 'backward'
    •  deprecate되었습니다.
    • 현재 페이지를 가져오는 방향 현재 페이지를 가져오는 방향에 액세스하려면 getNextPageParam 및 getPreviousPageParam에서 pageParam에 방향을 추가하십시오.

options

useQuery에는 다양한 옵션이 존재합니다. 아래 사이트에서 주요 옵션을 확인 할 수 있습니다.

https://github.com/ssi02014/react-query-tutorial?tab=readme-ov-file#usequery-%EC%A3%BC%EC%9A%94-%EC%98%B5%EC%85%98

 

GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리 - GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

github.com

const useSuperHeroData = (heroId) => {
  return useQuery({
    queryKey: ["super-hero", heroId],
    queryFn: () => getSuperHero(heroId),
    gcTime: 5 * 60 * 1000, // 5분
    staleTime: 1 * 60 * 1000, // 1분
    retry: 1,
    // ... options
  });
};

 

return data

useQuery는 쿼리 결과를 반환합니다. 템플릿화 및 데이터의 기타 사용에 필요한 모든 쿼리 정보가 포함되어 있습니다.

/* 주요 return data */
const {
  data,
  error,
  status,
  fetchStatus,
  isLoading,
  isFetching,
  isError,
  refetch,
  // ...
} = useQuery({
  queryKey: ["super-heroes"],
  queryFn: getAllSuperHero,
});
  • data: 쿼리 함수가 리턴한 Promise에서 resolved된 데이터
  • error: 쿼리 함수에 오류가 발생한 경우, 쿼리에 대한 오류 객체
  • status: data, 쿼리 결과값에 대한 상태를 표현하는 status는 문자열 형태로 3가지의 값이 존재한다.
    • pending: 쿼리 데이터가 없고, 쿼리 시도가 아직 완료되지 않은 상태.
      • { enabled: false } 상태로 쿼리가 호출되면 이 상태로 시작된다.
    • error: 에러 발생했을 때 상태
    • success: 쿼리 함수가 오류 없이 요청 성공하고 데이터를 표시할 준비가 된 상태.
  • fetchStatus: queryFn에 대한 정보를 나타냄
    • fetching: 쿼리가 현재 실행 중인 상태
    • paused: 쿼리를 요청했지만, 잠시 중단된 상태 (network mode와 연관)
    • idle: 쿼리가 현재 아무 작업도 수행하지 않는 상태
  • isLoading: 캐싱 된 데이터가 없을 때 즉, 처음 실행된 쿼리일 때 로딩 여부에 따라 true/false로 반환된다.
    • 이는 캐싱 된 데이터가 있다면 로딩 여부에 상관없이 false를 반환한다.
    • isFetching && isPending 와 동일하다.
  • isFetching: 캐싱 된 데이터가 있더라도 쿼리가 실행되면 로딩 여부에 따라 true/false로 반환된다.
  • isSuccess: 쿼리 요청이 성공하면 true
  • isError: 쿼리 요청 중에 에러가 발생한 경우 true
  • refetch: 쿼리를 수동으로 다시 가져오는 함수.
/* 사용 예시(1) */
<script setup>
import { useQuery } from '@tanstack/vue-query'

const { isPending, isError, data, error } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
</script>

<template>
  <span v-if="isPending">Loading...</span>
  <span v-else-if="isError">Error: {{ error.message }}</span>
  <!-- We can assume by this point that `isSuccess === true` -->
  <ul v-else-if="data">
    <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
  </ul>
</template>
/* 사용 예시(2) */
<script setup>
import { useQuery } from '@tanstack/vue-query'

const { status, data, error } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
</script>

<template>
  <span v-if="status === 'pending'">Loading...</span>
  <span v-else-if="status === 'error'">Error: {{ error.message }}</span>
  <!-- also status === 'success', but "else" logic works, too -->
  <ul v-else-if="data">
    <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
  </ul>
</template>

 

useQuery의 더 자세한 optionsreturn data를 확인하고 싶다면 아래 문서를 참고해주세요.

https://tanstack.com/query/latest/docs/framework/vue/reference/useQuery

 

useQuery | TanStack Query Vue Docs

Does this replace [Vuex, Pinia]? vue

tanstack.com

 

Mutations

기본적으로 서버에서 데이터를 GET 할 때는 useQuery를 사용합니다.

서버의 데이터를 POST, PATCH, PUT, DELETE와 같이 수정하고자 한다면 이때는 useMutation을 사용합니다.

  • useMutation의 반환 값인 mutate 메서드를 이용해서 요청 함수를 호출할 수 있습니다.
  • mutate 메서드의 인자로 넘긴 값은 mutationFn의 매개변수로 사용할 수 있습니다.
const { data, mutate } = useMutation({ 
  mutationFn, 
  // options ... 
})

mutate(variables, {
  onError,
  onSettled,
  onSuccess,
})

 

mutationFn

mutationFn은 비동기 작업을 수행하고 Promise를 반환하는 함수입니다.

mutationFn의 매개변수는 mutate를 통해 mutationFn에 전달될 객체입니다.

<script setup>
import { useMutation } from '@tanstack/vue-query'

const { isPending, isError, error, isSuccess, mutate } = useMutation({
  mutationFn: (newTodo) => axios.post('/todos', newTodo),
})

function addTodo() {
  mutate({ id: new Date(), title: 'Do Laundry' })
}
</script>

<template>
  <span v-if="isPending">Adding todo...</span>
  <span v-else-if="isError">An error occurred: {{ error.message }}</span>
  <span v-else-if="isSuccess">Todo added!</span>
  <button @click="addTodo">Create Todo</button>
</template>

 

  • Mutation 상태 Reset

경우에 따라 Mutation 요청의 오류 또는 데이터를 지우는 것이 필요할 수 있습니다. useMutation의 반환 값 중 reset() 함수를 사용하여 Mutation을 초기 상태로 재설정할 수 있습니다.

<script>
import { useMutation } from '@tanstack/vue-query'

const { error, mutate, reset } = useMutation({
  mutationFn: (newTodo) => axios.post('/todos', newTodo),
})

function addTodo() {
  mutate({ id: new Date(), title: 'Do Laundry' })
}
</script>

<template>
  <span v-else-if="error">
    <span>An error occurred: {{ error.message }}</span>
    <button @click="reset">Reset error</button>
  </span>
  <button @click="addTodo">Create Todo</button>
</template>

 

  • response data 핸들링

useMutation은 mutation의 라이프사이클 중 어떤 단계에서도 빠르고 쉬운 side-effect를 발생시킬 수 있는 옵션을 제공합니다.

useMutation({
  mutationFn: addTodo,
  onMutate: (variables) => {
    // A mutation is about to happen!
    // Optionally return a context containing data to use when for example rolling back
    return { id: 1 }
  },
  onError: (error, variables, context) => {
    // An error happened!
    console.log(rolling back optimistic update with id ${context.id})
  },
  onSuccess: (data, variables, context) => {
    // Boom baby!
  },
  onSettled: (data, error, variables, context) => {
    // Error or success... doesn't matter!
  },
})
  • onMutate: mutation 함수가 실행되기 전에 실행. mutation 함수가 받을 동일한 변수가 전달.
    • 뮤테이션이 성공하기를 기대하며 리소스에 대해 낙관적인 업데이트를 수행하는 데 유용.
    • 이 함수에서 반환된 값은 mutation 실패 시 onError 및 onSettled 함수에 전달.
      • 낙관적인 업데이트를 롤백하는 데 유용.
  • onError: mutation에서 오류가 발생했을 때 실행. 오류를 전달받음.
  • onSuccess: mutation이 성공했을 때 실행. 뮤테이션의 결과를 전달받음.
  • onSettled: mutation이 성공적으로 완료되거나 오류가 발생했을 때 실행. 데이터나 오류를 전달받음.
    • try...catch...finally 구문의 finally처럼 요청이 성공하든 에러가 발생하든 상관없이 마지막에 실행

낙관적 업데이트 (Optimistic Update)

서버 업데이트를 하기 전에 미리 화면의 UI를 바꿔준 후, 서버와의 통신 결과에 따라 확정 / 롤백을 결정하는 방식의 업데이트

서버 업데이트 시 UI에서도 어차피 업데이트 할 것이라고(낙관적) 가정해서 미리 UI를 업데이트 시켜주고 서버를 통해 검증받고 업데이트 또는 롤백하는 방식

  • 참고 문서

https://tanstack.com/query/latest/docs/framework/vue/guides/optimistic-updates

 

Optimistic Updates | TanStack Query Vue Docs

Vue Query provides two ways to optimistically update your UI before a mutation has completed. You can either use the onMutate option to update your cache directly, or leverage the returned variables to update your UI from the useMutation result. Via the UI

tanstack.com

https://velog.io/@pjh1011409/React-Query-%EB%82%99%EA%B4%80%EC%A0%81-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8

 

React Query - 낙관적 업데이트

🚀 Start 앞서 구현해본 쿼리 무효화를 통한 데이터 업데이트는 한가지 단점이 존재한다. 아래의 network 관리창을 확인해보면 appointments 데이터가 두번 통신한 것을 확인할 수 있다. 왜냐하면 한번

velog.io

https://github.com/ssi02014/react-query-tutorial?tab=readme-ov-file#optimistic-update

 

GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리 - GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

github.com

useMutation을 호출할 때 정의된 콜백 이외에 추가 콜백을 트리거하고 싶을 수 있습니다. 이를 위해 mutate 역시 동일한 콜백 옵션(onSuccess, onErroronSettled)을 제공합니다.

useMutation({
  mutationFn: addTodo,
  onSuccess: (data, variables, context) => {
    // I will fire first
  },
  onError: (error, variables, context) => {
    // I will fire first
  },
  onSettled: (data, error, variables, context) => {
    // I will fire first
  },
})

mutate(todo, {
  onSuccess: (data, variables, context) => {
    // I will fire second!
  },
  onError: (error, variables, context) => {
    // I will fire second!
  },
  onSettled: (data, error, variables, context) => {
    // I will fire second!
  },
})

useMutation의 Callback 함수와 mutate의 Callback 함수는 독립적으로 실행됩니다.

실행 순서는 useMutation의 Callback → mutate의 Callback 입니다.

  • 꼭 필요한 로직(ex. 쿼리 초기화)은 useMutation의 Callback으로 실행.
  • 리다이렉션 및 UI 관련 작업은 mutate Callback에서 실행.
  • Promise 형태의 response

만약, useMutation을 사용할 때 Promise 형태의 response가 필요하다면 mutateAsync를 사용하여 얻어올 수 있습니다.

const mutation = useMutation({ mutationFn: addTodo })

try {
  const todo = await mutation.mutateAsync(todo)
  console.log(todo)
} catch (error) {
  console.error(error)
} finally {
  console.log('done')
}

mutate와 mutateAsync 중 무엇을 사용하는게 좋을까?

useMutation은 mutate와 mutateAsync, 두 가지 함수를 제공합니다.

mutate는 아무것도 반환하지 않지만, mutateAsync는 변이 결과를 포함하는 Promise를 반환합니다. 따라서 Mutation 응답에 액세스해야 할 때 mutateAsync를 사용하려는 유혹이 있을 수 있지만, 대부분의 상황에서는 mutate를 사용하는 것이 좋습니다.

왜냐하면 mutate는 콜백(onSuccess, onError)를 통해 data와 error에 접근할 수 있기 때문에 우리가 특별히 핸들링해 줄 필요가 없기 때문입니다.

mutateAsync는 Promise를 직접 다루기 때문에 이런 에러 핸들링 같은 부분을 직접 다뤄야 합니다.

mutateAsync가 우수한 경우는 Promise가 필요한 경우뿐입니다. 이는 여러 Mutation을 동시에 실행하고 모두 완료될 때까지 기다리려는 경우나 콜백으로 인해 콜백 지옥에 빠질 수 있는 종속 변이가 있는 경우에 필요할 수 있습니다.

 

  • Mutation Retry

기본적으로 TanStack Query는 오류 발생 시 Mutation을 다시 시도하지 않지만 retry 옵션을 사용하여 재시도 할 수 있습니다.

const mutation = useMutation({
  mutationFn: addTodo,
  retry: 3,
})

 

useMutation의 더 자세한 optionsreturn data를 확인하고 싶다면 아래 문서를 참고해주세요.

https://tanstack.com/query/latest/docs/framework/vue/reference/useMutation

 

useMutation | TanStack Query Vue Docs

Does this replace [Vuex, Pinia]? vue

tanstack.com

 

Query Invalidation

vue-query는 쿼리가 유효한 상태일 경우 쿼리를 자동으로 다시 가져오지 않습니다. 하지만 데이터를 실시간으로 최신 상태로 유지해야 하는 경우가 있습니다. 이때 invalidateQueries 함수를 사용하여 강제로 쿼리를 무효화하고 다시 가져올 수 있게 할 수 있습니다.

 

invalidateQueries

캐시 데이터를 최신화 할 때 많이 사용하는 함수입니다.

invalidateQueries가 무효화하는 쿼리 범위는 기본적으로 상위 → 하위로 전파됩니다. 쿼리 키의 접두사를 사용하여 여러 쿼리를 일치시켜 다중으로 무효화 할 수 있습니다. 또는 정확한 쿼리를 일치시켜 단건만 무효화 할 수 있습니다.

 

쿼리 무효화 방법

  • 접두사가 일치하는 모든 쿼리 무효화
    • 아래 예는 queryKey가 todos로 시작하는 모든 쿼리를 무효화합니다.
 import { useQuery, useQueryClient } from '@tanstack/vue-query'

// Get QueryClient from the context
const queryClient = useQueryClient()

queryClient.invalidateQueries({ queryKey: ['todos'] })

// Both queries below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})
  • 변수가 있는 쿼리 무효화
    • invalidateQueries 메서드에 특정 변수를 사용한 더 구체적인 쿼리 키를 전달하여 쿼리를 무효화할 수도 있습니다.
queryClient.invalidateQueries({
  queryKey: ['todos', { type: 'done' }],
})

// 아래 쿼리는 무효화됩니다.
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

// 그러나 아래 쿼리는 무효화되지 않습니다.
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
  • 변수나 하위 키가 없는 쿼리 무효화
    • invalidateQueries 메서드에 exact: true 옵션을 전달하여 변수나 하위 키가 없는 쿼리만 무효화 할 수 있습니다.
queryClient.invalidateQueries({
  queryKey: ['todos'],
  exact: true,
})

// 아래 쿼리는 무효화됩니다.
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// 그러나 아래 쿼리는 무효화되지 않습니다.
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})
  • 쿼리 무효화 여부 판단
    • 더 세분성이 필요한 경우 invalidateQueries 메서드에 predicate 함수를 전달할 수도 있습니다.
      이 함수는 쿼리 캐시에서 각 쿼리 인스턴스를 받아 해당 쿼리를 무효화할지 여부에 대해 true 또는 false를 반환할 수 있습니다.
queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// 아래 쿼리는 무효화됩니다.
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// 아래 쿼리는 무효화됩니다.
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// 그러나 아래 쿼리는 무효화되지 않습니다.
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})

추가 참고 사항

QueryClient

캐시와 상호작용 하기 위해 사용되는 core API입니다.

기존 쿼리에 캐시된 데이터를 가져오거나, 캐싱된 쿼리 데이터를 즉시 갱신하거나, 캐시 데이터를 무효화하여 최신화하는 등 캐시와 관련된 유용한 기능을 제공합니다.

일반적으로 QueryClient의 옵션들을 이용할 때는 현재 QueryClient의 인스턴스를 반환하는 useQueryClient Hook을 사용합니다.

import { useQueryClient } from '@tanstack/vue-query'

const queryClient = useQueryClient(queryClient)

더 자세한 사항은 아래 문서를 확인해주세요.

 

QueryClient | TanStack Query Docs

fetchQuery is an asynchronous method that can be used to fetch and cache a query. It will either resolve with the data or throw with the error. Use the prefetchQuery method if you just want to fetch a query without needing the result. If the query exists a

tanstack.com

https://tanstack.com/query/latest/docs/framework/vue/reference/useQueryClient

 

useQueryClient | TanStack Query Vue Docs

Does this replace [Vuex, Pinia]? vue

tanstack.com

 

react-query-tutorial/document/queryClient.md at main · ssi02014/react-query-tutorial

😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리 - ssi02014/react-query-tutorial

github.com


참고하기 좋은 사이트

 

Overview | TanStack Query Vue Docs

TanStack Query (FKA Vue Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your web applications a breeze. Motivation Most

tanstack.com

 

GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리 - GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리

github.com

 

카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유 | 카카오페이 기술 블로그

카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유에 대해 설명합니다. 이 글은 연작 중 1편에 해당합니다. 1편: 카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유, 2편: React Que

tech.kakaopay.com

https://velog.io/@kim98111/useQuery

 

useQuery

Reqct Query의 동작 원리와 useQuery 훅 사용법에 대해서

velog.io

 

'FrontEnd > Vue.js' 카테고리의 다른 글

[vue-query] 추가 사항  (0) 2024.06.20
[용어] 스캐폴딩  (0) 2024.03.21