3. Fonctions load
Ok, notre application est capable de fournir des données au serveur, ainsi que les récupérer du serveur. Mais le fonctionnement actuel de notre application semble cassé : si on attrape un Pokémon, les informations du layout ne se mettent pas à jour... sauf en rechargeant manuellement la page. De même si vous essayez de supprimer un Pokémon :/
Pour comprendre et corriger ce problème, il faut commencer par comprendre plus précisément le rôle
des fonctions load
.
C'est quoi une fonction load
?
Nous avons vu ici le fonctionnement général de la navigation dans SvelteKit.
Pour rappel, à chaque navigation vers une URL gérée par SvelteKit, on charge les ressources de la page :
- le code HTML de la page (uniquement au premier chargement)
- les ressources statiques (CSS, images, ...)
- les scripts (notamment des composants)
- les données de page (fichiers
.json
)
Ces ressources ne sont chargées que si vous ne les avez pas déjà... sauf pour une : les données. Si
vous observez bien l'onglet "Réseau" de vos outils de développement navigateur, vous verrez que même
en faisant des aller-retours entre les pages, vous avez toujours un fichier .json
chargé pour
chaque navigation (seulement pour les pages ayant des données de page).
Nous parlons ici du comportement par défaut de SvelteKit. On verra qu'il est possible de changer ce comportement selon les besoins.
Ce fichier .json
contient les données de votre page, autrement dit ce fichier contient ce que
renvoie la fonction load
de la page en question.
Ce qui signifie que la fonction load
est jouée à chaque navigation vers la page. On peut donc
considérer que la fonction load
est le endpoint de la page.
De la même manière, les fonctions load
associées à des layout sont un peu comme des endpoints de
layout.
Mais ici, la fonction load
de layout ne se recharge pas, ce qui cause notre bug. C'est parce que
SvelteKit ne recharge que les fonctions load
qu'il estime ayant besoin d'être rechargées –
c'est-à-dire celles dont les dépendances ont changé. SvelteKit ne rechargera pas celles dont les
dépendances n'ont pas changé. Ce qui est le cas de notre load
de layout.
Dépendances des fonctions load
Quelque soit la fonction load
(de page ou de layout), vous pouvez récupérer des infos d'URL pour
déterminer les données que vous allez renvoyer. Par exemple :
export function load({ params, url }) {
const id = params.id;
const pathname = url.pathname;
const a = url.searchParams.get('a');
return { ... }
}
Les informations auxquelles vous avez accès dans une fonction
load
sont similaires à celles des fonctions de endpoint qu'on a vues ici.
Pour chaque page ou layout, SvelteKit est conscient des données params
ou url
dont vous avez
besoin, et va les considérer comme dépendances de la fonction load
en question.
SvelteKit ne rejoue les fonctions load
que si ses dépendances ont changé, ou si la page ou le
layout est reconstruit.
export function load({ url }) {
const nom = url.searchParams.get('nom');
// cette fonction est rejouée si on passe de "?nom=Monica" à "?nom=Janice"
// cette fonction n'est pas rejouée si on passe de "?nom=Romain&age=38" à "?nom=Romain&age=13"
return { ... }
}
Les conditions de ré-exécution d'une fonction sont plus complexes en réalité. Vous avez le détail ici.
Donc, si une fonction load
n'a pas de dépendances, (ou si ses dépendances n'ont pas changé lors
d'une navigation), alors elle ne sera pas ré-exécutée.
C'est le cas de notre layout, sa fonction
load
n'a pas de dépendances, et donc n'est jamais ré-exécutée.
Forcer la ré-exécution
Il y a des situations où des données ont besoin d'être mises à jour via une fonction load
, mais
celle-ci n'est pas ré-exécutée car SvelteKit de détecte pas de raison de le faire. La fonction
load
a alors une (ou plusieurs) dépendance implicite.
Dans ce cas, vous pouvez forcer la ré-exécution des fonctions load
en utilisant l'utilitaire
invalidateAll()
du module
$app/navigation
. Cette fonction permet de rejouter toutes les fonctions load
dont dépend la page
actuelle – celle de la page ainsi que celles de ses layouts éventuels.
import { invalidateAll } from `$app/navigation`;
function doSomeStuff() {
someStuff();
invalidateAll();
}
Toutefois, utiliser invalidateAll
est un peu violent, car cela amène à ré-exécuter des fonctions
load
qui n'en ont pas forcément besoin. Pour plus de granularité, il vaut mieux utiliser
invalidate()
du module
$app/navigation
.
import { invalidate } from `$app/navigation`;
function doSomeStuff() {
someStuff();
invalidate("some:url");
}
invalidate
prend un identifiant en argument de la forme "some:url"
. Toutes les fonctions load
ayant "some:url"
en dépendance seront alors ré-exécutées, les autres non.
Pour déclarer la dépendance d'une fonction load
à cet identificant, il faut utiliser depends
dans la fonction load
:
// +page.server.ts
export function load({ depends }) {
depends("some:url");
return {
...
}
}
Nous avons ainsi déclaré explicitement une dépendance implicite.
En réalité,
invalidate
prend une URL en argument, et il se trouve que le format"some:url"
est une URL valide.
Plus de détails sur ce chapitre :