React

Le runes di Svelte 5: stato, derivati ed effetti

Le runes sostituiscono le assegnazioni magiche di Svelte 4: state per lo stato, derived per i calcoli, effect solo per il DOM e le API esterne.

In sintesi

  • Le runes sono chiamate che il compilatore riconosce: funzionano solo in .svelte e .svelte.ts.
  • Un valore calcolato va in $derived, non in $effect: l’effetto serve per ciò che sta fuori dal componente.
  • $state avvolge oggetti in un proxy; $state.raw serve per dati grandi che sostituisci in blocco.

In Svelte 5 lo stato si dichiara con $state: la rune è una chiamata che il compilatore riconosce, non un let di cui indovina il ruolo. Da quella chiamata il compilatore sa cosa tracciare e cosa lasciare fermo.

Quattro runes coprono quasi tutto

$state per lo stato mutabile, $derived per i valori calcolati, $effect per gli effetti collaterali, $props per gli input del componente. $bindable, $inspect e $host servono in casi più stretti.

npx sv migrate svelte-5

  let { start = 0 }: { start?: number } = $props();
  let count = $state(start);
  const double = $derived(count * 2);


 (count += 1)}>Add one
{count} × 2 = {double}

$state avvolge oggetti e array in un proxy: le modifiche annidate sono tracciate. Per dati grandi che sostituisci in blocco c’è $state.raw; per passare un oggetto a una libreria esterna usa $state.snapshot, che restituisce una copia semplice.

Derived non è un effetto

$derived dichiara un valore, $derived.by accetta un blocco di codice. $effect gira dopo l’aggiornamento del DOM, solo nel browser, e serve per il DOM o per API esterne: usarlo per allineare due stati produce un ciclo che il compilatore non ti segnala.


  let query = $state("");
  let items = $state([]);

  const matches = $derived.by(() =>
    items.filter((item) => item.name.toLowerCase().includes(query.toLowerCase())),
  );

  $effect(() => {
    document.title = matches.length + " results";
  });

Props con $props e $bindable

let { title, value = 0 } = $props() dichiara gli input e i loro default. $bindable() rende una prop scrivibile da fuori: senza, l’assegnazione resta locale al figlio e il genitore non vede il cambio.

RunaScopoErrore tipico
$stateStato mutabile localeDichiararla in un .ts senza il suffisso .svelte
$derivedValore calcolatoAssegnarle un valore: è in sola lettura
$effectEffetti dopo il DOMSincronizzare due stati, che vuole un derivato
$propsInput del componenteLeggere una prop senza default e trovare un valore vuoto

Il limite da mettere in conto

Le runes esistono solo dove il compilatore le vede: nei file .svelte e in quelli con suffisso .svelte.ts. Un modulo .ts normale non può contenere $state, e $effect non gira durante il rendering sul server.

Errori che si vedono nella migrazione

  • Mescolare la sintassi vecchia e le runes nello stesso componente: in un componente con runes export let non è ammesso.
  • Scrivere dentro un $derived: il valore è in sola lettura e l’errore arriva a runtime.
  • Usare $effect per sincronizzare due stati: serve un $derived, l’effetto aggiunge un ciclo.
  • Leggere uno stato dopo un await dentro un effetto e aspettarsi che venga tracciato: la dipendenza va letta prima della pausa.

I componenti Svelte del catalogo sono già in questa forma: flowbite-svelte e svelte-bits si installano come sorgente, e il blocco form mostra il caso in cui lo stato locale basta. Il routing è in routing e layout in SvelteKit, il vecchio modello di store in store che non si aggiorna, il confronto in Svelte vs React.

Domande frequenti

Devo riscrivere tutti i componenti?

No. La modalità runes si attiva per componente e Svelte 5 compila ancora la sintassi vecchia. Riscrivi dove lo stato diventa difficile da seguire, non tutto in una volta.

$state o $state.raw?

$state per strutture che modifichi in profondità, raw per array e oggetti grandi che sostituisci in blocco. Raw non traccia le modifiche interne: riassegna il valore.

Perché $effect gira più volte?

Perché il primo giro registra le dipendenze e i successivi applicano il risultato. Se i giri sono troppi, l’effetto legge e scrive lo stesso stato: sposta il calcolo in un derivato.

Le runes funzionano in un file .ts?

Solo con il suffisso .svelte.ts, che passa dal compilatore. Un file .ts normale non viene processato e la rune resta una chiamata a una funzione che non esiste.

Svelte 5 è compatibile con le librerie Svelte 4?

In gran parte sì: i componenti vecchi continuano a compilare in modalità legacy. Il rischio sono le azioni che dipendono da this e i binding impliciti, che nelle runes non esistono più.