To-do list that remembers
A to-do list saved in the browser, with filters and a counter of what is left. The right exercise to save an array of objects and read it back without breaking anything.
- Save an array with JSON.stringify
- Read data back without crashing if it is corrupted
- Filter the display without touching the data
Pourquoi une liste qui se souvient ? La liste de tâches de base oublie tout au rechargement. Ici, chaque changement est enregistré dans localStorage, et la liste revient telle quelle le lendemain.
localStorage ne garde que du texte : on transforme le tableau en JSON pour l'écrire, et on le relit avec JSON.parse. Si le contenu est abîmé ou absent, on repart d'une liste vide plutôt que de planter.
Les filtres ne modifient jamais les données : ils choisissent seulement ce qu'on affiche.
Pourquoi en JavaScript simple ? Une fonction changer qui modifie, sauvegarde et redessine : un seul chemin pour toutes les actions. Dans la démo, le cadre isolé bloque le stockage, la liste y vit en mémoire.
LA CLÉ ET LA LECTURE
Un JSON abîmé ou absent ne doit pas faire planter la page.
const CLE = 'todo-memoire'; function charger() { try { const v = JSON.parse(localStorage.getItem(CLE)); return Array.isArray(v) ? v : []; } catch { return []; } } let taches = charger(), filtre = 'toutes';UN SEUL CHEMIN POUR CHANGER
Modifier, sauvegarder, redessiner : toujours dans cet ordre.
function changer(modifier) { modifier(); try { localStorage.setItem(CLE, JSON.stringify(taches)); } catch { /* stockage bloqué */ } rendre(); }LES ACTIONS
const ajouter = texte => changer(() => taches.push({ id: Date.now(), texte, fait: false })); const cocher = (id, fait) => changer(() => { taches.find(t => t.id === id).fait = fait; }); const supprimer = id => changer(() => { taches = taches.filter(t => t.id !== id); }); const purger = () => changer(() => { taches = taches.filter(t => !t.fait); });FILTRER À L'AFFICHAGE
Les données restent complètes, seul le rendu choisit.
function visibles() { if (filtre === 'afaire') return taches.filter(t => !t.fait); if (filtre === 'faites') return taches.filter(t => t.fait); return taches; }D'UN ONGLET À L'AUTRE
window.addEventListener('storage', e => { if (e.key === CLE) { taches = charger(); rendre(); } });
PIÈGE 1 : Sauvegarder l'objet directement
Mauvais : localStorage.setItem('taches', taches). On enregistre le texte « [object Object] » et tout est perdu.
Correct : JSON.stringify à l'écriture, JSON.parse à la lecture.
PIÈGE 2 : Faire confiance à ce qu'on relit
Mauvais : JSON.parse sans try. Une ancienne version, une extension ou une modification à la main, et la page reste blanche.
Correct : un try et catch, puis vérifier que c'est bien un tableau avant de s'en servir.
PIÈGE 3 : Filtrer les données
Mauvais : taches = taches.filter(...) quand on clique sur « À faire ». En revenant à « Toutes », les tâches faites ont disparu.
Correct : filtrer une copie au moment de l'affichage, jamais l'état lui-même.
- Une date d'échéance par tâche, et les retards en tête de liste.
- Le glisser-déposer pour réordonner, comme dans le tableau kanban.
- La modification au double clic, avec Échap pour annuler.
- Ajoutez un numéro de version dans ce que vous enregistrez : le jour où le format change, vous saurez convertir les anciennes listes.
- Pour des milliers d'éléments ou des fichiers, passez à IndexedDB, plus adapté que localStorage.
Le tableau vit dans un useState initialisé avec une fonction : useState(charger), pour ne lire qu'une fois.
Un useEffect sur taches écrit dans localStorage à chaque changement.
Le filtre est un autre useState, et la liste visible se calcule au rendu.
Loading comments…