Vue-query 소개 및 개념

강정우·2024년 4월 29일
0

vue.js

목록 보기
70/72
post-thumbnail
post-custom-banner

Vue-qeury

VueQuery는 React Query의 개념을 Vue.js 프레임워크에 적용한 것으로, 서버 상태 관리를 위한 라이브러리이다.
이는 Vue 애플리케이션에서 비동기적으로 데이터를 가져오고, 캐시하고, 동기화하는 과정을 쉽게 만들어 준다.

VueQuery 에서 제공하는 유용한 기능

1. 서버 상태 캐싱

자동으로 데이터를 캐시하여, 사용자가 같은 요청을 반복할 때 빠르게 응답을 제공한다.

2. 백그라운드 업데이트

애플리케이션의 다른 부분을 사용하면서 데이터를 최신 상태로 유지.

3. 데이터 동기화

여러 컴포넌트 간에 데이터를 쉽게 동기화.

4. 로딩 및 에러 상태 관리

데이터 요청의 로딩 상태와 에러 상태를 쉽게 관리할 수 있어, 사용자 인터페이스를 더욱 효과적으로 제어할 수 있다.

  • VueQuery를 사용하기 위해서는 Vue 3와 호환되는 버전을 설치해야 한다.
    기본 사용 골조는 여느 다른 상태관리 library 와 마찬가지로 Vue 컴포넌트 내에서 useQuery 훅을 사용하여 데이터를 요청하고, 반환된 데이터로 UI를 구성하면 된다.

VueQuery는 데이터를 중앙에서 관리하고, 애플리케이션의 효율성과 사용자 경험을 개선하는 데 도움을 줄 수 있는 강력한 도구이다.

질문 1. SSR 도 가능할까?

당연 가능하다. Vue.js 애플리케이션에서 SSR을 사용하면 초기 페이지 로드 시 서버에서 미리 HTML을 생성하여 전송함으로써, 사용자에게 더 빠른 콘텐츠 표시를 제공하고, 검색 엔진 최적화(SEO)에 유리한 조건을 만들 수 있다.

그러나 VueQuerySSR과 함께 사용할 때 주의할 점은 serverSCR에서 데이터를 동기화하는 방법을 잘 구현해야 한다.
이는 서버에서 데이터를 미리 가져오고, 해당 데이터를 초기 상태로 클라이언트에 전달한 후, 클라이언트 측에서 해당 상태를 기반으로 애플리케이션을 렌더링하는 과정을 포함한다.

VueQuery는 이러한 SSR 과정을 수월하게 만들어주는 기능들을 제공한다.
예를 들어, Hydrate와 dehydrate 함수를 사용하여, 서버에서 가져온 쿼리 상태를 클라이언트로 전달하고, 클라이언트에서 해당 상태를 사용하여 애플리케이션의 초기 상태를 구성할 수 있다.
이를 통해 서버와 클라이언트 사이의 데이터 동기화를 용이하게 하며, 사용자 경험을 향상시킬 수 있다.

따라서, VueQuery를 사용하면 SSR을 통해 애플리케이션의 성능과 SEO를 향상시키면서도, 데이터 관리의 복잡성을 줄일 수 있다.

질문 2. 기존에 상태관리 라이브러리를 대체할 수 있나?

이 질문은 공식문서에서 찾을 수 있었다. (Does this replace (Vuex, Pinia, etc)?)

Vue Query가 Vuex, Pinia 와 같은 글로벌 상태 관리자를 대체하는가에 대한 질문에 대해, 몇 가지 중요한 사항을 고려해야 한다고 한다.

Vue Query는 서버 상태 라이브러리로, 서버와 클라이언트 간의 비동기 작업을 관리하는 데 책임이 있다.
Vuex, Pinia, Zustand 등은 "클라이언트 상태 관리" 라이브러리로 물론 비동기 데이터를 저장하는 데 사용될 수 있지만, Vue Query와 같은 도구에 비해 비효율적일 수 있다.

Vue Query는 보일러 플레이트 코드와 클라이언트 상태에서 캐시 데이터를 관리하는 데 사용되는 관련 와이어링 코드 를 단 몇줄로 대체할 수 있다는 장점이 존재한다.

또 대부분의 애플리케이션에서, Vue Query로 비동기 코드를 모두 이전한 후에 남는 상태관리할 부분은 매우 작다고 자랑하고 있다.

예를 들어 관리해야할 globalState 가 projects, teams, tasks, users, themeMode, sidebarStatus 같다고 할 때 이를 vue query 를 사용하여 다 빼버리면 themeMode, sidebarStatus 뭐 이정도 남는데 딸랑 이걸 위해 pinia 혹은 vuex 를 사용하려면 해라 라는 형식으로 작성하고 있다.

그래서 Connectors, Action Creators, Middlewares, Reducers, Loading/Error/Result states, Contexts 들을 모두 작성하지 않다고 된다고 하는데

하지만, 애플리케이션의 전반적인 상태 관리(예: 사용자 인증 상태, 애플리케이션 내부의 UI 상태 등)에 대해서는 Pinia와 같은 다른 상태 관리 솔루션을 사용하는 것이 좋을 것 같다는 것이 아직은 내 생각이다.

왜냐하면 이러한 도구들은 애플리케이션 내에서 발생하는 다양한 상태를 보다 체계적으로 관리할 수 있도록 설계되었기 때문이다.

VueQuery는 서버 상태와 관련된 데이터를 효과적으로 관리할 수 있으며, 로컬 상태 관리에도 일부 사용될 수 있지만, 애플리케이션의 모든 상태 관리 요구사항을 충족시키기 위해서는 다른 상태 관리 솔루션과 함께 사용하는 것이 좋다.

그럼 이제 예재 코드들을 바탕으로 vue-query 를 하나하나 파헤쳐 보자.

1. quick start

<script setup>
import { useQueryClient, useQuery, useMutation } from "vue-query";

const queryClient = useQueryClient();

const useTodoQuery = () => {
  return useQuery(['todos'], fetchTodoList)
}

const { isLoading, isError, data, error, isFetching } = useTodoQuery()

const mutation = useMutation(postTodo, {
  onSuccess: () => {
    queryClient.invalidateQueries(["todos"]);
  },
});

const userInput = ref<string>('')

function postTodoBtnClick() {
  mutation.mutate({
    id: Date.now(),
    title: userInput.value,
  });
}
</script>

<template>
  <div class="greetings">
    <h2>
      <span v-if="isLoading">Loading...</span>
      <span v-else-if="isError">Error: {{ error.message }}</span>
      <span v-else-if="isFetching && !isLoading">Fetching...</span>
      <ul v-else>
        <li v-for="todo in data.todoList" :key="todo.id" style="color: #ffffff">{{ todo.todoTitle }}</li>
      </ul>
      <input v-model="userInput">
      <button @click="postTodoBtnClick">Add Todo</button>
    </h2>
  </div>
</template>

공식홈페이지에 들어가자마자 보이는 예제코드를 아주 조금 수정한 코드이다.

앞서 vue-query 의 특징을 설명했듯 보면 각각의 특징이 잘 나와있다.
우선 최초 페이지를 로딩할 때 "Loading..." 을 따로 Loading 표출 로직을 추가할 필요없이 간단하게 구조분해로 가져와서 표출할 수 있다.

그리고 또다른 특징으로는 Fetching... 이 있는데 이는 요청이 현재 진행 중인지 아닌지를 나타내는 boolean 값이다.
다른 페이지 혹은 tab 혹은 다른 application 을 클릭하고 다시 해당 웹페이지가 클릭되었을 때 즉, 데이터를 가져오는 중이지만 초기 로딩은 아닌 상태(백그라운드 데이터 갱신)를 UI에 표시하려면 자동으로 fetching 을 진행하는데 이때 동작하는 진행상태이다.

2. Important defaults

Important defaults 를 보면 자기내들이 얼마나 합리적이고 말이되는(이성적인) 라이브러리인지 소개하고 있다.

일단 뭔지는 모르겠지만 useQeury, useInfiniteQuery 를 사용한 값은 stale 로 간주되며 이는 주기적으로 백그라운드에서 자동으로 다시 요청된다.

예를 들어 앞서 내가 다른 페이지를 갔다가 오거나 특정 행동들을 하면 자동으로 백그라운드에서 패칭을 진행한다고 하였는데 바로 이 개념이다.

stale 들은 staleTime 옵션을 통해 이 동작을 조정할 수 있으며, staleTime 값을 길게 설정하면 데이터 재요청 빈도를 줄여 캐싱 메커니즘을 더 잘 제어하고 성능을 최적화할 수 있다.

  • 스테일 쿼리는 다음과 같은 경우에 백그라운드에서 자동으로 다시 요청된다
  1. 쿼리의 새 인스턴스가 마운트될 때
  2. 윈도우가 다시 foucus 되었을 때
  3. 네트워크가 다시 연결될 때
  4. 쿼리가 재요청 간격(refetch interval)으로 선택적으로 구성될 때

또한 refetchOnMount, refetchOnWindowFocus, refetchOnReconnect, refetchInterval 과 같은 옵션을 사용하여 이 기능을 변경할 수 있다.

만약 조회 결과가 useQuery, useInfiniteQuery 또는 query observers의 인스턴스가 아니라면 이는 inactive로 표시되며, 나중에 다시 필요할 경우를 대비해 캐시에 저장된다. 이때 5 분 후 가비지 컬렉션으로 보내진다.

  • 쿼리의 기본 cacheTime을 1000 60 5 밀리초가 아닌 다른 값으로 변경하여 이를 바꿀 수 있다.

만약 쿼리가 실패할 경우엔 몰래 3회를 재요청한다. 이때 UI 는 따로 변경되지 않는다.

  • 쿼리의 기본 retry 및 retryDelay 옵션을 변경하여 이를 조정할 수 있다.

쿼리 결과는 기본적으로 structurally shared를 사용하여 데이터가 실제로 변경되었는지 감지하고, 변경되지 않았다면 데이터 참조를 유지하여 값의 안정성을 더 높여준다. 뭔말인지 모르겠다면 그냥 넘어가자 왜냐하면 99.9%의 경우 이 기능을 비활성화할 필요가 없으며, 이 동작구조는 추가 비용 없이 앱의 성능을 향상시킬 수 있기 때문이다.

  • 참고로 구조적 공유는 JSON 호환 값에만 작동하며, 다른 모든 값 유형은 항상 변경된 것으로 간주된다.
    예를 들어, 대규모 응답으로 인한 성능 문제가 발생하는 경우, config.structuralSharing 플래그로 이 기능을 비활성화할 수 있다. 쿼리 응답에서 JSON과 호환되지 않는 값들을 다루고 있지만 데이터가 변경되었는지 여부를 감지하고 싶다면, config.isDataEqual로 데이터 비교 함수를 정의할 수 있다.

뭐 사실 학습곡선이 pinia, vuex 에 비해 높을 것 같다. 확실히 reference 도 적고 react 의 여러 복잡한 개념(useMemo, useHook, useQuery, useState etc...)들 중 하나를 채택하여 완성한 개념이기에 상태관리를 vue-query 로 시작하면 굉장히 헤맬것 같다.

하지만 공식문서 말대로 Connectors, Action Creators, Middlewares, Reducers, Loading/Error/Result states, Contexts 들을 모두 생략할 수 있다고 한다면 코드 생산속도가 굉장히 올라갈 것으로 기대가 된다.

물론 끝까지 파봐야겠지만 말이다.

profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글