Le système de composants de Svelte propose une approche spécifique de la réactivité et de l’initialisation des composants. Cet article explore une idée reçue concernant le fonctionnement des props, des variables et de l’initialisation des composants dans Svelte.
L’Idée Reçue
Les développeurs débutant avec Svelte pourraient supposer que lorsqu’une prop change, l’intégralité du script du composant s’exécute à nouveau, comme si le composant était une fonction et la prop un paramètre : si la prop change, la fonction donnera un autre résultat, n’est-ce pas ?
Ce n’est malheureusement pas ainsi que Svelte fonctionne.
Analyse de l’Exemple
L’exemple démontre ce concept avec deux composants :
- app.svelte : Un composant parent avec des boutons pour sélectionner différents noms
- name.svelte : Un composant enfant qui reçoit une prop de nom et qui indique si il y a des modifications
Le Composant Parent (app.svelte)
1<script>
2 // Ceci montre que changer la prop ne réexécute pas
3 // le script du composant.
4
5 import InputName from "./name.svelte";
6 let names = ["John", "Mila", "Ali"];
7 let selected = $state();
8</script>
9
10<!-- Ce sélecteur déclenche le changement de prop
11 dans le composant enfant -->
12{#each names as name}
13 <button onclick={() => selected=name}>{name}</button>
14{/each}
15
16<!-- Cette section appelle le composant enfant
17 avec la prop -->
18{#if selected}
19 <InputName name={selected}/>
20{/if}
Le composant parent :
- Maintient une liste de noms et un état de nom sélectionné
- Affiche des boutons pour chaque nom qui mettent à jour la variable
selected - Affiche également le composant
InputNameavec le nom sélectionné
Le Composant Enfant (name.svelte)
1<script>
2 // Composant simple avec indication de modification
3
4 let { name } = $props();
5
6 // exécuté une seule fois au montage du composant
7 let original = name;
8
9 let changed = $derived(original != name);
10</script>
11
12Nom : <input type="text" bind:value={name}>
13
14{#if changed}
15 modifié
16{/if}
Le composant enfant :
- Reçoit une prop
nameen utilisant$props() - Stocke la valeur initiale dans une variable
original - Utilise
$derivedpour créer une variable réactivechangedqui compare les valeurs actuelles et originales - Affiche “modifié” lorsque la valeur d’entrée diffère de l’original
Le Problème
Lorsque nous cliquons sur un nom et commençons à mettre à jour le champ, l’indicateur ‘modifié’ s’affiche. Cela semble fonctionner correctement.
Cependant, lorsque nous cliquons sur un autre nom, l’indicateur reste visible. Nous pouvons également déclencher ce problème en cliquant sur le premier nom sans le modifier, puis en cliquant sur un deuxième nom : l’indicateur ‘modifié’ apparaît alors que nous n’avons rien mis à jour.
L’élément clé est que le bloc script du composant ne s’exécute qu’une seule fois lors du montage initial du composant. Lorsque les props changent, Svelte met à jour les dépendances réactives sans réexécuter l’intégralité du script.
Cela signifie que let original = name; n’est exécuté qu’une seule fois lors de l’initialisation du composant. Lorsque la prop name change par la suite :
- La valeur de
nameest mise à jour - La valeur dérivée
changedest recalculée - Mais
originalconserve toujours la première valeur qu’elle a reçue
La Solution
Pour forcer le composant enfant à réexécuter son script lorsque la prop name change, nous utilisons un bloc {#key} dans le composant parent.
Le bloc {#key variable} se déclenche lors des mises à jour de variable en détruisant et en recréant les composants qu’il entoure.
Pour notre exemple, nous devons modifier notre code comme ceci :
1<!-- Cette section appelle le composant enfant avec la prop -->
2{#if selected}
3 {#key selected}
4 <InputName name={selected}/>
5 {/key}
6{/if}
Lorsque selected change :
- Sans
{#key}, la même instance de composant resterait etoriginalne serait jamais mise à jour - Avec
{#key}, Svelte détruit et recrée le composantInputName, ce qui entraîne une nouvelle exécution du script et une réinitialisation deoriginal
Conclusion
- Être conscient de l’initialisation unique : Les variables assignées directement dans le bloc script ne sont initialisées qu’une seule fois.
- Utiliser des déclarations réactives : Exploiter
$derivedpour les valeurs qui doivent réagir aux changements de props. - Comprendre quand utiliser
{#key}: L’utiliser lorsque vous devez réinitialiser complètement l’état d’un composant.