2. Réactivité des objects et des tableaux
Toujours à faire les intéressants ceux-là...
Vous pouvez bien sûr utiliser $state
pour déclarer un objet ({...}
) ou un tableau ([...]
).
Réactivité profonde
Avec les objets et les tableaux, vous pouvez notamment muter variable déclarée avec $state
et
quand même bénéficier de la réactivité. C'est ce qu'on appelle la réactivité profonde.
Par exemple, vous pouvez utiliser delete
pour supprimer une clé d'un objet, ou encore .push()
(ou autre) pour augmenter un tableau, et les mises à jour se feront normalement, comme attendu :
<script>
let obj = $state({ a: 1, b: 2 });
let arr = $state([1, 2]);
function update() {
delete obj.a;
arr.push(3);
}
</script>
<button onclick={update}> Update </button>
{#each Object.keys(obj) as k}
<!-- la clé 'a' est bien supprimée au clic sur le bouton -->
<p>{k}</p>
{/each}
{#each arr as nb}
<!-- le nombre d'éléments affichés augmente bien au clic sur le bouton `-->
<p>{nb}</p>
{/each}
En Svelte 4, la réactivité fonctionnait complètement différemment, et nécessitait l'usage d'une assignation (
truc = machin
) pour fonctionner. Écrire quelque chose commedelete obj.a
ouarr.push()
n'aurait eu aucun effet. Ajouter un élément à un tableau nécessitait donc d'écrire quelque chose commetableau = [...tableau, element]
.
Réactivité fine
En Svelte 4, il était possible de muter un objet (ou un tableau), à condition d'utiliser une assignation. Ceci est bien sûr toujours possible avec Svelte 5 :
<script>
let obj = $state({ a: 1, b: 2 });
function update() {
obj.a = 2;
}
</script>
<button onclick={update}> Update </button>
{#each Object.entries(obj) as [key, value]} <p>{key} : {value}</p> {/each}
Néanmoins, avec la rune $state
, la réactivité de Svelte 5 est "fine" (fine-grained). Cela
signifie que lorsqu'on mute une propriété d'un objet, cette propriété uniquement est "invalidée",
et non tout l'objet. En d'autres termes, uniquement les choses dont dépendent cette propriété
seront mises à jour, et non l'entièreté des dépendances de l'objet.
Cela permet d'optimiser la performance générale de votre application en évitant des calculs inutiles.
Voici un exemple simple du problème avec la réactivité de Svelte 4 :
<!-- Svelte 4 -->
<script>
let todos = [
{ done: false, text: 'Dormir' },
{ done: false, text: 'Manger' }
];
function getLength(arr) {
console.log('Calcul'); // inutilement ré-exécuté lorsqu'on met à jour les textes des tâches
return arr.length;
}
</script>
{#each todos as todo}
<div><input bind:value={todo.text} /> <input type="checkbox" bind:checked={todo.done} /></div>
{/each}
<p>Nombre de tâches : {getLength(todos)}</p>
Et son équivalent en Svelte 5 :
<!-- Svelte 5 -->
<script>
let todos = $state([
{ done: false, text: 'Dormir' },
{ done: false, text: 'Manger' }
]);
function getLength(arr) {
console.log('Calcul'); // n'est jamais recalculé si l'on change juste les textes
return arr.length;
}
</script>
{#each todos as todo}
<div><input bind:value={todo.text} /> <input type="checkbox" bind:checked={todo.done} /></div>
{/each}
<p>Nombre de tâches : {getLength(todos)}</p>
Vous trouverez une illustration plus complète de l'importance de cette différence ici (Svelte 4) versus là.