# Preserving state across routes

State survives a route change only when the component stays mounted: lift it above the router, or keep it in the URL, a context or storage.

> Page: https://ui.eneawork.it/blog/react-preservare-stato
> Markdown: https://ui.eneawork.it/blog/react-preservare-stato.md

*2026-11-01*

Lo stato sopravvive a un cambio di route solo se il componente che lo possiede resta montato: spostalo sopra il router, oppure mettilo nell’URL, in un context o nello storage, e decidi cosa deve azzerarsi.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, misurati da /api/stats il 1 novembre 2026. La cifra viene da una query all’endpoint, non da una stima: conta i record pubblicati e non dice quante route del catalogo conservino lo stato in modo esplicito.

## Quando React smonta, lo stato muore

Un cambio di route sostituisce l’elemento dentro Routes: il componente della pagina precedente viene smontato e con lui cadono useState, i valori delle ref e le cache locali. Non è un bug, è la stessa regola che azzera un form quando cambi pagina.

## Tre posti, tre costi

## Filtri nell’URL

import { useSearchParams } from "react-router"; const [params, setParams] = useSearchParams(); const page = Number(params.get("page") ?? "1"); const query = params.get("q") ?? ""; function setQuery(next) { setParams({ q: next, page: "1" }, { replace: true }); }

La pagina e il testo di ricerca arrivano dall’URL, quindi un reload non li perde e un link li porta con sé. replace evita una voce di cronologia per ogni tasto, altrimenti il tasto indietro diventa inutilizzabile.

## Lo stato che deve restare fuori

function App() { const [draft, setDraft] = useState(""); // survives route changes return ( ... ); }

Tutto ciò che sta sopra Routes non viene smontato: la bozza sopravvive alla navigazione. Metti lì solo lo stato che deve davvero durare, perché ogni valore trattenuto è memoria che non si libera.

## Il comando

npm create vite@latest router-demo -- --template react-ts cd router-demo npm install react-router npm run dev

React Router è distribuito con licenza MIT; il progetto parte con Vite e la route si dichiara in src/App.tsx. Il pacchetto react-router contiene già i componenti del browser, quindi non serve il vecchio react-router-dom.

## Record vivi nel catalogo

Tre record mostrano stato che vive oltre un singolo campo: expandable-tabs tiene la tab aperta, sidebar ricorda se è estesa, e la categoria input raccoglie i campi che quello stato lo producono.

## La limitazione

Nessuno dei tre posti è gratis: lo stato sopra il router trattiene memoria, l’URL finisce nella cronologia e nei log del server, lo storage richiede una versione e una scadenza. La scelta sbagliata si vede tardi, quando un utente torna su una pagina e trova i dati di un altro.

## Dove continuare

Le tab che vivono nell’URL sono in tab e URL; la navigazione da codice è in navigare con React Router; la stessa idea con i search params di Next.js è in paginazione e search params; il confronto fra i due setup è in Next.js vs Vite.

## FAQ

### Perché lo stato si perde cambiando route?

Perché il componente della pagina viene smontato e React elimina il suo stato. Solo ciò che resta montato conserva i valori.

### Conviene mettere i filtri nell’URL?

Sì quando l’utente deve condividere o ricaricare la vista. Costo: una scrittura di cronologia per aggiornamento, quindi usa replace e un debounce.

### Dove metto una bozza di form da conservare?

Sopra il router se serve solo durante la sessione, in sessionStorage se deve sopravvivere a un reload, sul server se deve durare oltre la sessione.

### Conservare tutto in un context è una buona idea?

No. Il context trattiene tutto finché l’app resta aperta e ogni aggiornamento rirenderizza chi lo legge: metti solo lo stato davvero condiviso.

### Lo stato nell’URL è sicuro?

È pubblico: finisce nella cronologia, nei log e nei link condivisi. Non metterci token, email o dati personali.
