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 TanStack 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ésultats d'une requête pour l'afficher instantanément à l'utilisateur lors de visites successives :
- Lors du premier chargement d'une ressource les données sont mises en mémoire et associées à 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 nouvelles 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érez les données. C'est à vous d'implémenter cette partie là. La librairie ne se charge que de la mise en cache et de proposer une fonction composable utile.
Utilisation
Pour commencer à utiliser TranStack Query on l'ajoute 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 contenus
<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 aux requêtes, 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érations (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>