TanStack Query (Vue Query)

При создании сложного приложения на Vue.js на ряде страниц (в ряде компонентов) могут понадобиться общие для части проекта данные. При этом они не настолько общие и часто употребимые, чтобы загружать их сразу при обращении к любой странице. Хорошо бы загрузить эти данные сразу при посещении одной из тех страниц, где они нужны. И далее хранить с возможностью использовать на других страницах без повторной загрузки.

Например, в приложении есть возможность оплаты, есть список тарифов и список платежных систем. В кабинете администратора (админке) происходит настройка показа тарифов и платежных систем пользователям. Данные о платежных системах могут понадобится и на странице настройки тарифов (если не все тарифы доступны для каждой платежной системы) и на странице настройки географии показа платежных систем и, возможно, где-то еще. При этом на массе других страниц эти данные будут совершенно лишними, грузить их там не стоит.

Один из подходов, который мы могли бы тут применить – добавить модуль в хранилище Vuex, получать данные при необходимости и описать их кеширование. Такой путь может потребовать некоторой рутинной работы по описанию данного взаимодействия. Если запрос к серверу длится несколько секунд, то надо продумать и отображение какой-либо анимации загрузки. В общем может появиться ряд неожиданных проблем.

Можно пойти иным путем. В книге “Learn React with TypeScript” описан пакет React Query. Данный пакет позволяет задать данным любое имя (ключ) и получать их от сервера только если кеш пуст или истек. Для Vue, как оказалось, есть такой пакет тоже. Vue Query, который мигрировал в TanStack Query.

В пакете представлен хук useQuery, который делает запрос к серверу и помещает данные в кеш (в ОЗУ). При следующем запросе к хранилищу данные будут сразу выданы из кеша и, если кеш устарел, то будет сделан запрос к серверу. Таким образом, общие данные, полученные с сервера один раз, будут выдаваться из кеша пока страница не будет перезагружена.

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

// Access QueryClient instance
const queryClient = useQueryClient()

// Query
const { isPending, isError, data, error } = useQuery({
  queryKey: ['todos'],
  queryFn: getTodos,
})

// Mutation
const mutation = useMutation({
  mutationFn: postTodo,
  onSuccess: () => {
    // Invalidate and refetch
    queryClient.invalidateQueries({ queryKey: ['todos'] })
  },
})

function onButtonClick() {
  mutation.mutate({
    id: Date.now(),
    title: 'Do Laundry',
  })
}
</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>
    <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
  </ul>
  <button @click="onButtonClick">Add Todo</button>
</template>

Описание получения данных происходит в блоке useQuery:

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

Здесь можно выделить следующие части:

  • queryKey задает ключ, по которому эти данные будут доступны. Ключ может быть составным, поэтому – массив
  • queryFn задает функцию, которая получает данные с сервера в случае, когда кеш устарел
  • isPending, isError, data, error – переменные с результатами и состоянием результата. data – сами данные, которые затем используются в шаблоне. isPending помогает отобразить анимацию загрузки.

Как можно видеть из примера, в пакете есть и способ сделать кеш устаревшим. Кстати, для управления временем жизни кеша есть 2 параметра: cacheTime (5 минут по-умолчанию) и staleTime (0 по-умолчанию, что означает “немедленно”). Первый задает время, в течение которого кеш вообще может храниться, а второй – как быстро кеш будет помечаться устаревшим.

При обращении к устаревшим данным они будут выданы сразу же из кеша, но после этого будет сделан запрос в фоне, чтобы получить свежие данные. Это позволяет отобразить данные быстро (за счет пользования слегка устаревшими данными) и при этом обновлять их не мешая пользователю. Вы вольны управлять этими параметрами как вам нужно. Для этого нужно решить на сколько свежие данные вам нужно показывать пользователю.

У пакета очень широкие возможности, которые не ограничиваются выборкой и кешированием. Также есть возможность менять данные (mutate), задавать количество повторных запросов при ошибках, реализовывать оптимистическое обновление UI до завершения операции сохранения (мутации), реализовывать “бесконечную” прокрутку и пагинацию. А также многое другое, что может вам пригодится при работе с данными, получаемыми от сервера. За подробностями всегда можно обратиться к документации.

Обновление от 2024-02-13

Если использовать вместо Vuex новый рекомендуемый пакет – Pinia, то в этом случае, за счет поддержки нескольких хранилищ, часть озвученных проблем будет решена. Мы сможем подключить нужное хранилище только в нужных местах. Однако, TanStack Query также умеет обновлять устаревшие данные после выдачи сохраненных данных.

Вероятно, и для Pinia вскоре появится плагин, который позволяет установить политику устаревания части данных и получение их из первоисточника. Если в приложении такое потребуется, то надо иметь в виду оба этих инструмента.

Оставить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *