Filtrer les dépenses par catégorie
Objectif : Afficher uniquement les dépenses correspondant à la catégorie sélectionnée.
Une liste de dépenses peut vite devenir difficile à parcourir. Vous allez ajouter un filtre par catégorie pour n’afficher, par exemple, que les dépenses de transport, sans supprimer les autres du tableau de bord.
Le tableau `depenses` reste la collection complète. Le filtre est une valeur séparée, mémorisée une seule fois dans le composant parent. À chaque changement, vous calculez une liste à afficher à partir de ces deux données. La dépense présente dans le tableau d’origine reste donc disponible lorsque vous choisissez une autre catégorie.
Mémoriser la catégorie choisie
L’état du filtre appartient à `App`, car ce composant possède déjà le tableau des dépenses et transmet les données à la liste. La valeur spéciale `toutes` signifie qu’aucune catégorie particulière n’est sélectionnée. Les autres valeurs correspondent aux catégories des dépenses.
import { useState } from "react";
import EnteteDepenses from "./composants/EnteteDepenses";
import FormulaireDepense from "./composants/FormulaireDepense";
import FiltresDepenses from "./composants/FiltresDepenses";
import RecapitulatifMensuel from "./composants/RecapitulatifMensuel";
import ListeDepenses from "./composants/ListeDepenses";
export type Depense = {
id: string;
description: string;
montant: number;
categorie: string;
date: string;
};
export default function App() {
const [depenses, setDepenses] = useState<Depense[]>([
{
id: "depense-1",
description: "Courses",
montant: 42.5,
categorie: "Alimentation",
date: "2025-03-12",
},
]);
const [categorieSelectionnee, setCategorieSelectionnee] = useState("toutes");
function ajouterDepense(nouvelleDepense: Depense) {
setDepenses((depensesActuelles) => [...depensesActuelles, nouvelleDepense]);
}
const depensesFiltrees =
categorieSelectionnee === "toutes"
? depenses
: depenses.filter((depense) => depense.categorie === categorieSelectionnee);
const categories = Array.from(new Set(depenses.map((depense) => depense.categorie)));
return (
<div className="depenses-app">
<EnteteDepenses />
<main className="depenses-principale">
<FormulaireDepense ajouterDepense={ajouterDepense} />
<RecapitulatifMensuel />
<FiltresDepenses
categories={categories}
categorieSelectionnee={categorieSelectionnee}
onCategorieChange={setCategorieSelectionnee}
/>
<ListeDepenses depenses={depensesFiltrees} />
</main>
</div>
);
}La méthode `filter` parcourt le tableau et renvoie un nouveau tableau contenant uniquement les dépenses pour lesquelles la condition est vraie. Ici, la condition compare la catégorie de chaque dépense à la sélection. Quand la sélection vaut `toutes`, le code transmet directement le tableau complet à la liste.
Transmettre le filtre au composant dédié
Le composant `FiltresDepenses` présente le sélecteur et signale à `App` la nouvelle valeur. Il ne possède pas de copie de l’état : il reçoit la sélection en prop et appelle la fonction reçue quand la personne choisit une catégorie. Le filtrage reste ainsi coordonné avec les données de la page.
type FiltresDepensesProps = {
categories: string[];
categorieSelectionnee: string;
onCategorieChange: (categorie: string) => void;
};
export default function FiltresDepenses({
categories,
categorieSelectionnee,
onCategorieChange,
}: FiltresDepensesProps) {
return (
<section className="depenses-filtres" aria-label="Filtres des dépenses">
<label>
Filtrer par catégorie
<select
className="depenses-filtres__select"
name="filtre-categorie"
value={categorieSelectionnee}
onChange={(evenement) => onCategorieChange(evenement.target.value)}
>
<option value="toutes">Toutes les catégories</option>
{categories.map((categorie) => (
<option key={categorie} value={categorie}>
{categorie}
</option>
))}
</select>
</label>
</section>
);
}Vérifier le résultat
Avec la dépense de démonstration « Courses », la catégorie « Alimentation » affiche cette dépense, tandis que « Transport » produit une liste filtrée vide. Le composant de liste existant affiche alors son message d’état vide. Après l’ajout d’une dépense, les catégories disponibles sont recalculées à partir du tableau complet, et la nouvelle catégorie peut être sélectionnée.
- Le filtre est un état unique détenu par `App`.
- `filter` crée le tableau affiché sans modifier la collection complète.
- La valeur `toutes` permet de revenir à l’ensemble des dépenses.
- Le sélecteur transmet le choix au parent et la liste reçoit les dépenses filtrées.