Leçon 10 / 15

Filtrer les dépenses par catégorie

20 min React — composants et état Gratuit

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.

Texte
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.

Texte
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.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.