Introduzione
Quando costruiamo un’applicazione web, spesso vogliamo che l’utente non perda il contesto del lavoro svolto. Un caso molto comune è la gestione dello stato di ricerca e dei filtri: ad esempio, una pagina con risultati prodotti, una lista di articoli, una dashboard o un catalogo possono avere un campo di ricerca, filtri per categoria, ordinamento e paginazione. Se l’utente ricarica la pagina o torna indietro, è utile ripristinare questi dati senza costringerlo a reinserirli ogni volta.
In questo tutorial vediamo come usare LocalStorage e SessionStorage per salvare in modo semplice lo stato di una ricerca. Il vantaggio è pratico: miglioriamo l’esperienza utente con pochissimo codice, senza bisogno di un backend. Il tema è perfetto per capire quando usare una persistenza lunga, come LocalStorage, e quando invece preferire una memorizzazione temporanea, come SessionStorage.
L’obiettivo sarà salvare e ripristinare:
- testo cercato;
- categoria selezionata;
- ordinamento scelto;
- stato della pagina corrente.
Vedrai anche come strutturare i dati in modo pulito, come evitare errori con JSON.stringify e JSON.parse, e come scegliere tra i due storage in base al comportamento desiderato.
Codice completo
Qui sotto trovi un esempio completo di una pagina che gestisce una ricerca con filtri e salva lo stato in LocalStorage oppure in SessionStorage a seconda di una modalità configurabile.
// Simuliamo un piccolo catalogo
const products = [
{ id: 1, name: "Mouse wireless", category: "accessori", price: 25 },
{ id: 2, name: "Tastiera meccanica", category: "accessori", price: 90 },
{ id: 3, name: "Monitor 27 pollici", category: "hardware", price: 220 },
{ id: 4, name: "SSD 1TB", category: "hardware", price: 110 },
{ id: 5, name: "Corso JavaScript", category: "formazione", price: 49 },
];
// Chiave unica per salvare lo stato
const STORAGE_KEY = "search-ui-state";
// Cambia qui per usare localStorage o sessionStorage
const storage = localStorage; // oppure sessionStorage
// Elementi UI
const searchInput = document.querySelector("#search");
const categorySelect = document.querySelector("#category");
const sortSelect = document.querySelector("#sort");
const resetButton = document.querySelector("#reset");
const resultsList = document.querySelector("#results");
// Stato iniziale
let state = {
query: "",
category: "all",
sort: "name-asc",
};
// Salva lo stato nello storage scelto
function saveState() {
storage.setItem(STORAGE_KEY, JSON.stringify(state));
}
// Carica lo stato dallo storage
function loadState() {
const raw = storage.getItem(STORAGE_KEY);
if (!raw) return;
try {
const parsed = JSON.parse(raw);
state = { ...state, ...parsed };
} catch (error) {
console.warn("Stato non valido, resetto i dati salvati:", error);
storage.removeItem(STORAGE_KEY);
}
}
// Filtra e ordina i prodotti
function getFilteredProducts() {
let filtered = products.filter((product) => {
const matchesQuery = product.name
.toLowerCase()
.includes(state.query.toLowerCase());
const matchesCategory =
state.category === "all" || product.category === state.category;
return matchesQuery && matchesCategory;
});
filtered.sort((a, b) => {
if (state.sort === "price-asc") return a.price - b.price;
if (state.sort === "price-desc") return b.price - a.price;
return a.name.localeCompare(b.name);
});
return filtered;
}
// Render della lista risultati
function renderResults() {
const items = getFilteredProducts();
resultsList.innerHTML = "";
if (items.length === 0) {
resultsList.innerHTML = "<li>Nessun risultato trovato</li>";
return;
}
items.forEach((item) => {
const li = document.createElement("li");
li.textContent = `${item.name} - ${item.category} - €${item.price}`;
resultsList.appendChild(li);
});
}
// Aggiorna la UI con lo stato corrente
function syncUI() {
searchInput.value = state.query;
categorySelect.value = state.category;
sortSelect.value = state.sort;
renderResults();
}
// Eventi UI
searchInput.addEventListener("input", (event) => {
state.query = event.target.value;
saveState();
renderResults();
});
categorySelect.addEventListener("change", (event) => {
state.category = event.target.value;
saveState();
renderResults();
});
sortSelect.addEventListener("change", (event) => {
state.sort = event.target.value;
saveState();
renderResults();
});
resetButton.addEventListener("click", () => {
state = {
query: "",
category: "all",
sort: "name-asc",
};
storage.removeItem(STORAGE_KEY);
syncUI();
});
// Inizializzazione
loadState();
syncUI(); Per far funzionare questo script, l’HTML della pagina potrebbe essere molto semplice, ad esempio con un input, due select, un pulsante e una lista risultati. L’importante è che gli id corrispondano a quelli usati nel JavaScript.
Spiegazione
Il codice si basa su un’idea semplice: tenere tutto lo stato in un unico oggetto JavaScript e sincronizzarlo con lo storage del browser ogni volta che cambia.
1. Lo stato dell’interfaccia
Abbiamo definito un oggetto state con tre proprietà:
- query: il testo inserito nella ricerca;
- category: la categoria selezionata;
- sort: il criterio di ordinamento.
Questo approccio è molto utile perché centralizza i dati. Invece di spargere valori in più punti del codice, abbiamo una sola fonte di verità.
2. Salvare i dati nello storage
LocalStorage e SessionStorage salvano solo stringhe. Per questo usiamo JSON.stringify(state) quando scriviamo i dati. In questo modo trasformiamo l’oggetto in una stringa JSON valida.
La funzione saveState() si occupa di aggiornare lo storage ogni volta che l’utente modifica un filtro o la ricerca. È una soluzione semplice e diretta.
3. Ripristinare lo stato
Quando la pagina si carica, la funzione loadState() legge il valore salvato con getItem(). Se il dato esiste, viene convertito di nuovo in oggetto con JSON.parse().
È importante gestire gli errori: se il contenuto nello storage è corrotto o non è un JSON valido, JSON.parse() può fallire. Per questo usiamo un blocco try/catch e, in caso di problema, rimuoviamo il dato errato.
4. Aggiornare la UI
La funzione syncUI() serve a riportare i valori salvati nei controlli della pagina. Dopo aver caricato lo stato, impostiamo:
- valore dell’input;
- valore della select categoria;
- valore della select ordinamento.
Subito dopo richiamiamo renderResults() per mostrare i risultati coerenti con lo stato recuperato.
5. Differenza tra LocalStorage e SessionStorage
La differenza pratica è molto importante:
- LocalStorage: i dati restano salvati anche dopo la chiusura del browser, finché non vengono rimossi manualmente;
- SessionStorage: i dati durano solo per la sessione corrente e spariscono quando la scheda viene chiusa.
Per uno stato di ricerca, questa scelta dipende dall’esperienza desiderata. Se vuoi che l’utente ritrovi i filtri anche domani, usa LocalStorage. Se invece vuoi mantenere lo stato solo mentre la scheda è aperta, usa SessionStorage.
Best practice
- Salva un solo oggetto di stato: è più facile da mantenere rispetto a molte chiavi separate nello storage.
- Valida sempre i dati letti: non fidarti mai ciecamente del contenuto salvato.
- Usa try/catch con JSON.parse: evita che un dato corrotto blocchi l’applicazione.
- Non salvare dati sensibili: password, token di autenticazione o informazioni private non dovrebbero stare in LocalStorage o SessionStorage.
- Preferisci SessionStorage per stati temporanei: ad esempio filtri di una ricerca breve o preferenze utili solo nella sessione.
- Limita la frequenza di scrittura: se lo stato cambia molto spesso, valuta un debounce per ridurre le chiamate a storage.
- Rimuovi i dati inutili: quando lo stato non serve più, usa removeItem() per evitare accumuli non necessari.
Un’altra buona pratica è distinguere chiaramente tra dati applicativi e dati di presentazione. Lo storage del browser è perfetto per piccoli stati UI, ma non è un database. Se i dati diventano complessi o critici, meglio usare un backend o un sistema di persistenza più robusto.
Riepilogo
LocalStorage e SessionStorage sono strumenti semplici ma molto utili per salvare lo stato di una ricerca e dei filtri in un’app web. Con poche righe di JavaScript possiamo:
- salvare i valori inseriti dall’utente;
- ripristinarli al caricamento della pagina;
- migliorare l’esperienza utente;
- scegliere tra persistenza lunga o temporanea.
La strategia migliore è tenere lo stato in un oggetto unico, serializzarlo con JSON, validarlo al recupero e aggiornare la UI in modo coerente. Questo approccio è pulito, scalabile e facile da adattare a cataloghi, dashboard, liste di contenuti e applicazioni con filtri dinamici.
Approfondisci con risorse ufficiali
- MDN Web Docs - Window.localStorage: documentazione ufficiale su LocalStorage.
- MDN Web Docs - Window.sessionStorage: documentazione ufficiale su SessionStorage.
- MDN Web Docs - JSON.stringify(): per serializzare oggetti in stringhe JSON.
- MDN Web Docs - JSON.parse(): per convertire JSON in oggetti JavaScript.
- MDN Web Docs - Web Storage API: panoramica completa sull’API di storage del browser.
