Si vous êtes habitué•e•s à construire des applications web uniquement côté client, la gestion de l'état dans une application qui s'étend à la fois sur le serveur et sur le client peut paraître intimidante. Cette section fournit des astuces pour éviter quelques pièges classiques. ## Éviter les états partagés sur le serveur [!VO]Avoid shared state on the server Les navigateurs sont _stateful_, c-à-d qu'ils sont capables de gérer de l'état — l'état est stocké en mémoire au fur et à mesure que l'utilisateur ou utilisatrice interagit avec l'application. Les serveurs, en revanche, sont _stateless_, c-à-d qu'ils ne peuvent pas gérer de l'état — le contenu d'une réponse est entièrement déterminé par le contenu de la requête. En tout cas, conceptuellement. En réalité, les serveurs sont souvent des processus qui restent actifs longtemps et qui sont partagés par de nombreuses personnes les consommant. Pour cette raison, il est important de ne pas y stocker de données dans des varibles partagées. Par exemple, considérez ce bout de code : ```js // @errors: 7034 7005 /// file: +page.server.js let user; /** @type {import('./$types').PageServerLoad} */ export function load() { return { user }; } /** @satisfies {import('./$types').Actions} */ export const actions = { default: async ({ request }) => { const data = await request.formData(); // NE FAITES JAMAIS ÇA ! user = { name: data.get('name'), embarrassingSecret: data.get('secret') }; } } ``` La variable `user` est partagée — donc accessible — par toute personne se connectant au serveur. Si Alice a envoyé un secret embarrassant, et Bob visite la page un peu après, Bob va être au courant du secret d'Alice. De plus, lorsqu'Alice va revenir sur le site plus tard dans la journée, le serveur peut avoir été réinitialisé, perdant ses données. Vous devriez plutôt _authentifier_ l'utilisateur ou utilisatrice en utilisant des [`cookies`](load#Cookies) et persister les données dans une base de données. ## Pas d'effets de bord dans les fonctions `load` [!VO]No side-effects in load Pour la même raison, vos fonctions `load` devraient être _pures_ — donc ne comporter aucun effet de bord (à l'exception peut-être d'un `console.log(...)` occasionnel). Par exemple, vous pourriez être tenté•e d'écrire dans un store ou un état global à l'intérieur d'une fonction `load` afin de pouvoir réutiliser la valeur dans vos composants : ```js /// file: +page.js // @filename: ambient.d.ts declare module '$lib/user' { export const user: { set: (value: any) => void }; } // @filename: index.js // ---cut--- import { user } from '$lib/user'; /** @type {import('./$types').PageLoad} */ export async function load({ fetch }) { const response = await fetch('/api/user'); // NE FAITES JAMAIS ÇA ! user.set(await response.json()); } ``` Comme avec l'exemple précédent, ceci enregistre les informations d'une personne dans un endroit qui est partagé avec _tout le monde_. Vous devriez plutôt simplement renvoyer les données... ```js /// file: +page.js /** @type {import('./$types').PageServerLoad} */ export async function load({ fetch }) { const response = await fetch('/api/user'); +++ return { user: await response.json() };+++ } ``` ... et les passer aux composants qui en ont besoin, ou bien utiliser [`page.data`](load#page.data). Si vous n'utilisez pas le SSR, il n'y a alors pas de risques d'exposer accidentellement les données d'une personne à d'autres personnes. Mais vous devriez tout de même éviter les effets de bord dans vos fonctions `load` — le flux de données dans votre application sera bien plus facile à suivre. ## Utiliser des états et des stores avec le contexte [!VO]Using state and stores with context Vous pourriez vous demander comment nous sommes capables d'utiliser `page.data` et d'autres [états d'application]($app-state) (ou [stores d'application]($app-stores)) s'il ne faut pas utiliser d'état global. La réponse est que les états et stores d'application sur le serveur utilisent l'[API de contexte](/tutorial/svelte/context-api) de Svelte — l'état (ou le store) est attaché à l'arbre de composant avec `setContext`, et lorsque vous vous y abonnez, vous le lisez avec `getContext`. Nous pouvons faire la même chose avec nos propres états : ```svelte ``` ```svelte
Welcome {user().name}
``` > [!NOTE] Nous passons une fonction dans `setContext` pour garder la réactivité entre les frontières > des composants. Apprenez-en plus [ici](/docs/svelte/$state#Passing-state-into-functions) > [!LEGACY] > Vous pouvez aussi utiliser des stores importés depuis `svelte/store` avec cette technique, mais si > vous utilisez Svelte 5, il est plutôt recommandé d'utiliser la réactivité universelle. Mettre à jour la valeur d'un état stocké en contexte dans des pages ou composants profonds lors du rendu côté de la page ne va pas affceter la valeur de cet état dans le composant parent car il aura déjà été rendu au moment où la valeur est mise à jour. A contrario, sur le client (lorsque le CSR est activé, ce qui est le cas par défaut), la valeur sera propagée, et les composants, pages, layouts situés plus haut dans la hiérarchie vont pouvoir réagir à cette nouvelle valeur. En conséquence, pour éviter des "flashs" liés à la mise à jour de valeur pendant l'hydratation, il est généralement recommandé de passer les états des parents vers les enfants plutôt que dans l'autre sens. Si vous n'utilisez pas le SSR (et pouvez garantir que vous n'utiliserez pas le SSR dans le futur), vous pouvez alors conserver vos états dans un module partagé en toute sécurité, sans utiliser l'API de contexte. ## L'état des pages et composants est préservé [!VO]Component and page state is preserved Lorsque vous naviguez dans votre application, SvelteKit réutilise les composants de layout et de page déjà existants. Par exemple, si vous avez une route comme celle-ci... ```svelteTemps de lecture : {Math.round(estimatedReadingTime)} minutes