14 juillet 2026 · Nuxt · Gestion d'état
Gestion d'état dans Nuxt : useState, bonnes pratiques et pièges
useState, partage compatible SSR, pollution inter-requêtes, quand sortir Pinia : les règles pour gérer l'état d'une application Nuxt sans se tirer une balle dans le pied.
En Vue côté client, on partage souvent un état en déclarant un ref dans un
module et en l'important où on veut. Ça marche très bien dans le navigateur,
et ça casse silencieusement dès qu'on passe au rendu serveur. Comprendre
pourquoi, c'est comprendre toute la gestion d'état de Nuxt.
Le piège du ref partagé en module
// state.ts - À NE PAS FAIRE en SSR
import { ref } from 'vue'
export const utilisateur = ref(null)
Côté client, ce ref est unique : un seul navigateur, un seul état. Côté
serveur, le processus Node est partagé entre tous les visiteurs. Ce
ref unique devient alors un état commun à toutes les requêtes
simultanées : l'utilisateur A voit les données de l'utilisateur B. C'est une
fuite de données inter-requêtes, et elle est très difficile à repérer parce
qu'elle n'apparaît pas en développement local avec un seul onglet.
useState : l'état partagé fait pour le SSR
La réponse de Nuxt est useState. Il crée un état réactif isolé par
requête côté serveur, et correctement transféré (sérialisé puis hydraté)
vers le client :
// app/composables/useUtilisateur.ts
export function useUtilisateur() {
return useState('utilisateur', () => null)
}
Deux détails comptent. Le premier argument est une clé unique : deux appels avec la même clé partagent le même état, c'est le mécanisme de partage. Le second argument est une fonction d'initialisation, pas une valeur directe : elle n'est appelée qu'une fois, au bon moment du cycle SSR.
L'envelopper dans un composable useUtilisateur() évite de répéter la clé
partout et centralise le point d'accès. Si un jour la clé change, un seul
fichier bouge.
useFetch et useAsyncData : l'état, c'est aussi les données
La majorité de l'état d'une application, ce sont des données distantes. Ne
les gérez pas à la main avec un ref plus un onMounted plus un try/catch.
useFetch fait tout cela, et de façon compatible SSR :
<script setup lang="ts">
const { data: articles, status, error } = await useFetch('/api/articles')
</script>
Il récupère les données côté serveur au premier rendu (donc le HTML arrive
déjà rempli, bon pour le SEO), les transfère au client sans refetch, et
gère le cache et la déduplication via une clé. Deux composants qui appellent
useFetch avec la même URL ne déclenchent qu'une seule requête. Traiter les
données comme un état géré par le framework, plutôt que comme du code
impératif, élimine une classe entière de bugs.
Quand sortir Pinia
useState couvre l'état simple et partagé. Passez à Pinia (le store
officiel de l'écosystème Vue) quand l'état devient un domaine à part
entière :
- de la logique métier autour de l'état (actions, règles, validations) et pas seulement une valeur ;
- des valeurs dérivées nombreuses (des
gettersqui se recalculent) ; - un besoin de structurer par modules (panier, session, préférences) avec chacun son état, ses actions, ses getters ;
- l'envie d'outils de débogage dédiés et d'un point d'entrée testable isolément.
Le critère n'est pas la taille de l'application mais la nature de
l'état : une poignée de valeurs partagées, useState suffit ; un domaine
avec de la logique, Pinia paie son coût.
Quelques pièges concrets
- Ne mettez pas de valeur non sérialisable dans
useState. L'état transite du serveur au client en JSON. Une instance de classe, une fonction ou uneDatene survivent pas au voyage. Stockez des données simples et reconstruisez les objets riches côté client si besoin. - Attention aux clés qui se chevauchent. Deux
useState('data', ...)dans deux contextes différents partagent le même état par accident. Nommez les clés comme un espace de noms :'panier','session-user','prefs-theme'. - N'accédez pas à
windowoulocalStorageà l'initialisation. Ce code s'exécute aussi côté serveur, où ces objets n'existent pas. Pour un état persistant côté navigateur,useCookiefonctionne des deux côtés ; sinon, gardez l'accès au stockage dansonMounted.
La leçon
La gestion d'état en Nuxt se résume à une prise de conscience : votre code
tourne côté serveur autant que côté client, et un état mal isolé fuit entre
les requêtes. À partir de là, tout s'ordonne : useState pour l'état
partagé simple, useFetch pour les données distantes, Pinia quand l'état
devient un domaine. Le ref global de module, lui, reste dans les projets
purement client. Choisissez l'outil selon la portée de l'état, pas selon
l'habitude.