Tanstack Vue Query

Voir la vidéo
Description Sommaire

Dans ce chapitre je vous propose de découvrir une librairie incontournable lorsqu'il s'agit de récupérer des données tiers avec VueJS : TanStack Query.

00:00 Présentation
01:35 Installation de TranStack Query
02:00 La fonction useQuery()
09:50 Invalidation du cache
14:18 Les mutations (useMutation())
18:52 Pagination infinie (useInfiniteQuery())

Pourquoi cette librairie ?

Dans la plupart des cas une application front-end va avoir besoin de récupérer des données depuis un serveur et de les afficher à l'utilisateur mais plusieurs pages peuvent avoir besoin de même données et gérer cela via un état global peut s'avérer complexe. TanStack Query apporte un système de cache global qui permet de garder en mémoire les résultat d'une requête pour l'afficher instantanément à l'utilisateur lors de visite successive :

  • Lors du premier chargement d'une ressource les données sont mises en mémoire et associée à une clef.
  • Si la même requête est chargée, les données en cache sont utilisées pendant que TanStack Query demande les nouvelle données au serveur.
  • Lorsque les nouvelles données arrivent, le cache est remplacé et la page est mise à jour.

Il est important de noter que TanStack Query n'a pas d'opinion sur comment vous récupérer les données. C'est à vous d'implémenter cette partie là. La librairie ne se charger que de la mise en cache et de proposer une fonction composable utile.

Utilisation

Pour commencer à utiliser TranStack Query on l'ajouter aux dépendances du projet.

$ npm i @tanstack/vue-query
# or
$ bun add @tanstack/vue-query

Puis on l'ajoute comme plugin à notre projet VueJS

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

app.use(VueQueryPlugin)

Une fois chargé, on pourra utiliser la fonction composable useQuery() pour gérer le chargement de nos contenu

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

const {data, isLoading, isFetching, isError, error} = useQuery({
    queryKey: ['posts'],
    queryFn: () => getPosts({page: 1})
})
</script>

La clef permet de retrouver la requête plus tard pour pouvoir invalider le cache ou le mettre à jour. Par défaut une requête est considérée comme "périmée" dès sa récupération mais il est possible de modifier ce comportement à l'aide du paramètre staleTime.

const {data, isLoading, isFetching, isError, error} = useQuery({
    queryKey: ['posts'],
    queryFn: () => getPosts({page: 1}),
    staleTime: 30_000, // Temps avant que le cache soit considéré comme périmé (0 par défaut)
    gcTime: 60_000, // Durée de vie du cache (5 min par défaut)
})

Pourquoi ces propriétés ?

  • Un cache périmé est utilisé pendant que les nouvelles données sont récupérées, l'utilisateur voit les anciennes données pendant le chargement des nouvelles données.
  • Un cache supprimé fait que l'utilisateur ne voit plus le contenu lors du second affichage d'une requête.

Mutation

Lorsque l'on souhaitera mettre à jour des données il sera possible d'utiliser la fonction composable useMutation().

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

const { isLoading, isError, error, isSuccess, mutate } = useMutation({
  mutationFn: (data) => updatePost(props.id, data),
})

const handleSubmit = (e) => {
    mutate(new FormData(e.target))
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <!-- ... -->
    <button type="submit">Mettre à jour l'article</button>
  </form>
</template>

Contrairement au requête une mutation ne s'exécute pas au montage du composant mais seulement lorsque la méthode mutate ou mutateAsync est appelée. Il n'y a pas non plus de mise en cache.

Invalidation

Le problème de la mise en cache est que les données peuvent changer lorsque l'utilisateur effectue certaines opération (traitement de formulaire par exemple). Dans ce cas là il est possible d'invalider manuellement le cache depuis le client.

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

const queryClient = useQueryClient();

const handleSubmit = async () => {
    // Mis à jour des données sur le serveur
    await updatePost(new FormData(e.target))
    // On invalide les données concernant les articles
    await queryClient.invalidateQueries(
      {
        queryKey: ['posts'],
      }
    )
}

Il est aussi possible de venir modifier les données dans le cache pour un retour instantané auprès de l'utilisateur. L'inconvénient est qu'il faut s'assurer de le faire pour toutes les requêtes qui peuvent contenir les données.

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

const queryClient = useQueryClient();

const handleSubmit = async () => {
    // Mis à jour des données sur le serveur
    await updatePost(new FormData(e.target))
    // On invalide les données concernant les articles
    await queryClient.setQueryData(['posts'], (oldData) => {
         // Génère les nouvelles données et les retourne
         return newData
    })
}

Pagination infinie

Enfin, une dernière fonctionnalité intéressante de TanStack Query est la possibilité de mettre en place facilement une pagination infinie grâce à la fonction useInfiniteQuery().

<script>
const {
  fetchNextPage,
  hasNextPage,
  isLoading,
  isFetching,
  hasNextPage,
  // Data contient l'ensemble des pages
  data,
} = useInfiniteQuery({
  queryKey: ['posts'],
  initialPageParam: 1,
  queryFn: ({ pageParam }) => getPosts({page: pageParam}),
  // Doit renvoyer null si il n'y a pas de page suivante
  getNextPageParam: (lastPage, pages) => pages.length + 1
})

// On peut récupèrer les articles sous forme de liste à plat 
const posts = computed(() => data.value?.pages.flat())
</script>

<template>
<main>
  <Spinner v-if="isLoading"/>
  <div class="posts" v-else>
     <PostCard v-for="post in posts" :key="post.id" :post="post"/>
  </div>
  <button @click="fetchNextPage" :disabled="isFetching" v-if="hasNextPage">Page suivante</button>
</main>
</template>
Publié
Technologies utilisées
Auteur :
Grafikart
Partager