# Svelte: the store does not update, assignment, update and context

Svelte reacts to assignments, not to mutations inside an object. Change an object in the store without calling `set` or `update` and the UI stays as it is.

> Page: https://ui.eneawork.it/blog/svelte-store-non-si-aggiorna
> Markdown: https://ui.eneawork.it/blog/svelte-store-non-si-aggiorna.md

*2026-11-01*

Risposta breve: Svelte notifica gli iscritti soltanto quando qualcuno chiama set o update sullo store. Se muti un oggetto al suo interno, il riferimento resta lo stesso e la UI non si accorge di niente.

Il tag svelte conta 6.284 domande e astrojs 752 sulla Stack Exchange API al 31 ottobre 2026: ecosistemi più piccoli, ma con gli stessi errori di reattività. Il catalogo EneUI misura 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account. I conteggi sono stati verificati con una chiamata diretta all'endpoint, non copiati da una bozza precedente.

## Il meccanismo: lo store non guarda dentro

Uno store è una scatola con due cose: un valore e una lista di funzioni in ascolto. La scatola non ha occhi. Non sa che hai chiamato push su un array che contiene, perché nessuno glielo dice: la notifica nasce dalla chiamata a set, non dal contenuto.

Il compilatore applica la stessa logica allo stato locale: riscrive le assegnazioni in invalidazioni. Un metodo che muta un array non è un'assegnazione, quindi non produce invalidazione. Ecco perché l'errore ha la stessa faccia nello store e nel componente.

import { writable } from "svelte/store"; export const cart = writable({ items: [] }); // non notifica nessuno: il riferimento non cambia cart.value.items.push(item);

cart.value non esiste: lo store non espone il valore come proprietà. La versione reale dell'errore è più silenziosa e usa get(cart).items.push(item), che restituisce la nuova lunghezza dell'array e non emette nulla.

## Diagnosi: chiedi allo store, non alla UI

Prima di toccare il componente, verifica se lo store ha emesso. Una sottoscrizione manuale con un log separa i due lati del problema in un minuto, senza aprire il debugger.

import { get } from "svelte/store"; import { cart } from "$lib/stores/cart"; const stop = cart.subscribe((value) => { console.log("emit", value.items.length); }); get(cart).items.push("probe"); // nessun log: la scrittura non emette stop();

Se il log non compare, il difetto è nella scrittura e la UI sta facendo il suo lavoro. Se compare ma il testo resta vecchio, il componente legge una copia: const items = $cart.items valuta il valore una volta e non segue i cambiamenti del campo.

## La correzione: un oggetto nuovo

// 1. update: il modo idiomatico per gli oggetti cart.update((c) => ({ ...c, items: [...c.items, item] })); // 2. set con un nuovo riferimento cart.set({ items: [...get(cart).items, item] });

Entrambe le righe costruiscono un array nuovo dentro un oggetto nuovo. La UI reagisce perché cambia l'identità, non perché il contenuto sia diverso. Non è una preferenza di stile: è il contratto, e vale anche per set chiamato da un modulo.

## Il prefisso $ e i confini del compilatore

import { cart } from "$lib/stores/cart"; {$cart.items.length} articoli

Il $ è zucchero sintattico: il compilatore lo sostituisce con una sottoscrizione e con il suo annullamento allo smontaggio. Fuori da un componente non esiste. In un modulo .js usa get(cart) per leggere una volta, oppure subscribe se ti serve il flusso.

## Svelte 5: rune e store convivono

$state copre lo stato locale di un componente; uno store resta lo strumento per condividere stato fra componenti lontani. La sintassi $store funziona ancora nei file .svelte, mentre in un modulo la runa non si applica. Scegli un modello per tipo di stato e scrivilo nel readme, altrimenti ogni nuovo file riapre la discussione.

## Quando la correzione comune peggiora le cose

La scorciatoia più diffusa è mutare dentro update e restituire lo stesso oggetto. Lo store emette, il componente che lo legge si ridisegna, e il caso sembra chiuso. I figli memoizzati però ricevono lo stesso riferimento di prima e non ridisegnano: il sintomo si sposta di un livello, e lo ritrovi in una tabella che non cambia.

La seconda è il clone profondo a ogni scrittura, con structuredClone o con il giro JSON. Perde Date, Map e istanze di classe, e su una lista lunga costa un attraversamento completo per ogni tasto premuto.

## Un limite da mettere in conto: nessuna granularità

Gli store notificano per valore, non per campo. Se un unico store contiene filtri, righe e selezione, ogni scrittura sveglia tutti gli iscritti. Non esiste un selettore nativo come nelle librerie di state management: la granularità si ottiene spezzando lo store. Su un catalogo grande il costo si legge nel profiler dei componenti, non nella console.

## Prevenzione

## Dove continuare

Nel catalogo: componenti, blocco pricing e blocchi. Le guide: checklist accessibilità e UI kit, libreria o design system; il confronto: copy-paste o headless.

## FAQ

### Perché `store.value = x` non aggiorna la UI?

Perché quella proprietà non esiste sullo store: il valore si legge con get e si scrive con set. Un oggetto senza set non emette, quindi nessun iscritto viene chiamato.

### `update` e `set` sono equivalenti?

No. `set` sostituisce il valore con quello che riceve, `update` riceve il valore corrente e ne restituisce uno nuovo. Con gli oggetti annidati `update` evita una lettura separata.

### Perché `$store` è undefined in un file .js?

La sintassi del dollaro viene compilata solo dentro i componenti. In un modulo importi lo store e chiami get, oppure ti iscrivi con subscribe e annulli la sottoscrizione alla fine.

### Devo riscrivere tutto con le rune in Svelte 5?

No. Gli store restano supportati e sono ancora la scelta naturale per lo stato condiviso. Le rune servono per lo stato locale, non sostituiscono un contenitore globale.

### Come debuggo un aggiornamento mancante?

Aggiungi una sottoscrizione con un log e prova una scrittura. Se non arriva nessun log il difetto è nella scrittura; se arriva e la pagina resta ferma, il componente legge una copia locale.
