[{"data":1,"prerenderedAt":460},["ShallowReactive",2],{"article-\u002Fblog\u002Fgestion-etat-nuxt-bonnes-pratiques":3},{"id":4,"title":5,"body":6,"brouillon":446,"date":447,"description":448,"extension":449,"image":450,"imageAlt":450,"meta":451,"navigation":452,"path":453,"seo":454,"stem":455,"tags":456,"__hash__":459},"blog\u002Fblog\u002Fgestion-etat-nuxt-bonnes-pratiques.md","Gestion d'état dans Nuxt : useState, bonnes pratiques et pièges",{"type":7,"value":8,"toc":435},"minimark",[9,18,26,91,105,112,122,175,186,193,204,220,307,313,317,326,346,356,360,415,419,431],[10,11,12,13,17],"p",{},"En Vue côté client, on partage souvent un état en déclarant un ",[14,15,16],"code",{},"ref"," dans un\nmodule et en l'important où on veut. Ça marche très bien dans le navigateur,\net ça casse silencieusement dès qu'on passe au rendu serveur. Comprendre\npourquoi, c'est comprendre toute la gestion d'état de Nuxt.",[19,20,22,23,25],"h2",{"id":21},"le-piège-du-ref-partagé-en-module","Le piège du ",[14,24,16],{}," partagé en module",[27,28,33],"pre",{"className":29,"code":30,"language":31,"meta":32,"style":32},"language-typescript shiki shiki-themes github-dark","\u002F\u002F state.ts  - À NE PAS FAIRE en SSR\nimport { ref } from 'vue'\nexport const utilisateur = ref(null)\n","typescript","",[14,34,35,44,62],{"__ignoreMap":32},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sAwPA","\u002F\u002F state.ts  - À NE PAS FAIRE en SSR\n",[36,45,47,51,55,58],{"class":38,"line":46},2,[36,48,50],{"class":49},"snl16","import",[36,52,54],{"class":53},"s95oV"," { ref } ",[36,56,57],{"class":49},"from",[36,59,61],{"class":60},"sU2Wk"," 'vue'\n",[36,63,65,68,71,75,78,82,85,88],{"class":38,"line":64},3,[36,66,67],{"class":49},"export",[36,69,70],{"class":49}," const",[36,72,74],{"class":73},"sDLfK"," utilisateur",[36,76,77],{"class":49}," =",[36,79,81],{"class":80},"svObZ"," ref",[36,83,84],{"class":53},"(",[36,86,87],{"class":73},"null",[36,89,90],{"class":53},")\n",[10,92,93,94,96,97,101,102,104],{},"Côté client, ce ",[14,95,16],{}," est unique : un seul navigateur, un seul état. Côté\nserveur, le processus Node est ",[98,99,100],"strong",{},"partagé entre tous les visiteurs",". Ce\n",[14,103,16],{}," unique devient alors un état commun à toutes les requêtes\nsimultanées : l'utilisateur A voit les données de l'utilisateur B. C'est une\nfuite de données inter-requêtes, et elle est très difficile à repérer parce\nqu'elle n'apparaît pas en développement local avec un seul onglet.",[19,106,108,111],{"id":107},"usestate-létat-partagé-fait-pour-le-ssr",[14,109,110],{},"useState"," : l'état partagé fait pour le SSR",[10,113,114,115,117,118,121],{},"La réponse de Nuxt est ",[14,116,110],{},". Il crée un état réactif ",[98,119,120],{},"isolé par\nrequête"," côté serveur, et correctement transféré (sérialisé puis hydraté)\nvers le client :",[27,123,125],{"className":29,"code":124,"language":31,"meta":32,"style":32},"\u002F\u002F app\u002Fcomposables\u002FuseUtilisateur.ts\nexport function useUtilisateur() {\n  return useState('utilisateur', () => null)\n}\n",[14,126,127,132,145,169],{"__ignoreMap":32},[36,128,129],{"class":38,"line":39},[36,130,131],{"class":42},"\u002F\u002F app\u002Fcomposables\u002FuseUtilisateur.ts\n",[36,133,134,136,139,142],{"class":38,"line":46},[36,135,67],{"class":49},[36,137,138],{"class":49}," function",[36,140,141],{"class":80}," useUtilisateur",[36,143,144],{"class":53},"() {\n",[36,146,147,150,153,155,158,161,164,167],{"class":38,"line":64},[36,148,149],{"class":49},"  return",[36,151,152],{"class":80}," useState",[36,154,84],{"class":53},[36,156,157],{"class":60},"'utilisateur'",[36,159,160],{"class":53},", () ",[36,162,163],{"class":49},"=>",[36,165,166],{"class":73}," null",[36,168,90],{"class":53},[36,170,172],{"class":38,"line":171},4,[36,173,174],{"class":53},"}\n",[10,176,177,178,181,182,185],{},"Deux détails comptent. Le ",[98,179,180],{},"premier argument est une clé"," unique : deux\nappels avec la même clé partagent le même état, c'est le mécanisme de\npartage. Le ",[98,183,184],{},"second argument est une fonction"," d'initialisation, pas une\nvaleur directe : elle n'est appelée qu'une fois, au bon moment du cycle SSR.",[10,187,188,189,192],{},"L'envelopper dans un composable ",[14,190,191],{},"useUtilisateur()"," évite de répéter la clé\npartout et centralise le point d'accès. Si un jour la clé change, un seul\nfichier bouge.",[19,194,196,199,200,203],{"id":195},"usefetch-et-useasyncdata-létat-cest-aussi-les-données",[14,197,198],{},"useFetch"," et ",[14,201,202],{},"useAsyncData"," : l'état, c'est aussi les données",[10,205,206,207,209,210,209,213,216,217,219],{},"La majorité de l'état d'une application, ce sont des données distantes. Ne\nles gérez pas à la main avec un ",[14,208,16],{}," plus un ",[14,211,212],{},"onMounted",[14,214,215],{},"try\u002Fcatch",".\n",[14,218,198],{}," fait tout cela, et de façon compatible SSR :",[27,221,225],{"className":222,"code":223,"language":224,"meta":32,"style":32},"language-vue shiki shiki-themes github-dark","\u003Cscript setup lang=\"ts\">\nconst { data: articles, status, error } = await useFetch('\u002Fapi\u002Farticles')\n\u003C\u002Fscript>\n","vue",[14,226,227,251,298],{"__ignoreMap":32},[36,228,229,232,236,239,242,245,248],{"class":38,"line":39},[36,230,231],{"class":53},"\u003C",[36,233,235],{"class":234},"s4JwU","script",[36,237,238],{"class":80}," setup",[36,240,241],{"class":80}," lang",[36,243,244],{"class":53},"=",[36,246,247],{"class":60},"\"ts\"",[36,249,250],{"class":53},">\n",[36,252,253,256,259,263,266,269,272,275,277,280,283,285,288,291,293,296],{"class":38,"line":46},[36,254,255],{"class":49},"const",[36,257,258],{"class":53}," { ",[36,260,262],{"class":261},"s9osk","data",[36,264,265],{"class":53},": ",[36,267,268],{"class":73},"articles",[36,270,271],{"class":53},", ",[36,273,274],{"class":73},"status",[36,276,271],{"class":53},[36,278,279],{"class":73},"error",[36,281,282],{"class":53}," } ",[36,284,244],{"class":49},[36,286,287],{"class":49}," await",[36,289,290],{"class":80}," useFetch",[36,292,84],{"class":53},[36,294,295],{"class":60},"'\u002Fapi\u002Farticles'",[36,297,90],{"class":53},[36,299,300,303,305],{"class":38,"line":64},[36,301,302],{"class":53},"\u003C\u002F",[36,304,235],{"class":234},[36,306,250],{"class":53},[10,308,309,310,312],{},"Il récupère les données côté serveur au premier rendu (donc le HTML arrive\ndéjà rempli, bon pour le SEO), les transfère au client sans refetch, et\ngère le cache et la déduplication via une clé. Deux composants qui appellent\n",[14,311,198],{}," avec la même URL ne déclenchent qu'une seule requête. Traiter les\ndonnées comme un état géré par le framework, plutôt que comme du code\nimpératif, élimine une classe entière de bugs.",[19,314,316],{"id":315},"quand-sortir-pinia","Quand sortir Pinia",[10,318,319,321,322,325],{},[14,320,110],{}," couvre l'état simple et partagé. Passez à Pinia (le store\nofficiel de l'écosystème Vue) quand l'état devient un ",[98,323,324],{},"domaine"," à part\nentière :",[327,328,329,333,340,343],"ul",{},[330,331,332],"li",{},"de la logique métier autour de l'état (actions, règles, validations) et\npas seulement une valeur ;",[330,334,335,336,339],{},"des valeurs dérivées nombreuses (des ",[14,337,338],{},"getters"," qui se recalculent) ;",[330,341,342],{},"un besoin de structurer par modules (panier, session, préférences) avec\nchacun son état, ses actions, ses getters ;",[330,344,345],{},"l'envie d'outils de débogage dédiés et d'un point d'entrée testable\nisolément.",[10,347,348,349,352,353,355],{},"Le critère n'est pas la taille de l'application mais la ",[98,350,351],{},"nature de\nl'état"," : une poignée de valeurs partagées, ",[14,354,110],{}," suffit ; un domaine\navec de la logique, Pinia paie son coût.",[19,357,359],{"id":358},"quelques-pièges-concrets","Quelques pièges concrets",[327,361,362,375,395],{},[330,363,364,370,371,374],{},[98,365,366,367,369],{},"Ne mettez pas de valeur non sérialisable dans ",[14,368,110],{},"."," L'état\ntransite du serveur au client en JSON. Une instance de classe, une\nfonction ou une ",[14,372,373],{},"Date"," ne survivent pas au voyage. Stockez des données\nsimples et reconstruisez les objets riches côté client si besoin.",[330,376,377,380,381,384,385,271,388,391,392,369],{},[98,378,379],{},"Attention aux clés qui se chevauchent."," Deux ",[14,382,383],{},"useState('data', ...)","\ndans deux contextes différents partagent le même état par accident.\nNommez les clés comme un espace de noms : ",[14,386,387],{},"'panier'",[14,389,390],{},"'session-user'",",\n",[14,393,394],{},"'prefs-theme'",[330,396,397,408,409,412,413,369],{},[98,398,399,400,403,404,407],{},"N'accédez pas à ",[14,401,402],{},"window"," ou ",[14,405,406],{},"localStorage"," à l'initialisation."," Ce code\ns'exécute aussi côté serveur, où ces objets n'existent pas. Pour un état\npersistant côté navigateur, ",[14,410,411],{},"useCookie"," fonctionne des deux côtés ; sinon,\ngardez l'accès au stockage dans ",[14,414,212],{},[19,416,418],{"id":417},"la-leçon","La leçon",[10,420,421,422,424,425,427,428,430],{},"La gestion d'état en Nuxt se résume à une prise de conscience : votre code\ntourne côté serveur autant que côté client, et un état mal isolé fuit entre\nles requêtes. À partir de là, tout s'ordonne : ",[14,423,110],{}," pour l'état\npartagé simple, ",[14,426,198],{}," pour les données distantes, Pinia quand l'état\ndevient un domaine. Le ",[14,429,16],{}," global de module, lui, reste dans les projets\npurement client. Choisissez l'outil selon la portée de l'état, pas selon\nl'habitude.",[432,433,434],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":32,"searchDepth":46,"depth":46,"links":436},[437,439,441,443,444,445],{"id":21,"depth":46,"text":438},"Le piège du ref partagé en module",{"id":107,"depth":46,"text":440},"useState : l'état partagé fait pour le SSR",{"id":195,"depth":46,"text":442},"useFetch et useAsyncData : l'état, c'est aussi les données",{"id":315,"depth":46,"text":316},{"id":358,"depth":46,"text":359},{"id":417,"depth":46,"text":418},false,"2026-07-14","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.","md",null,{},true,"\u002Fblog\u002Fgestion-etat-nuxt-bonnes-pratiques",{"title":5,"description":448},"blog\u002Fgestion-etat-nuxt-bonnes-pratiques",[457,458],"Nuxt","Gestion d'état","ihNvcDqGs6Bw_Po635w67cxCJfCqxO-qiJgBxrfmGII",1784652014639]