📋 Rendre des listes avec .map()

Pour afficher une liste d'éléments en React, on utilise .map() pour transformer chaque élément en JSX.

const fruits = ['Pomme', 'Banane', 'Cerise'];

function ListeFruits() {
  return (
    <ul>
      {fruits.map(fruit => (
        <li key={fruit}>{fruit}</li>
      ))}
    </ul>
  );
}

// Avec des objets
const utilisateurs = [
  { id: 1, nom: 'Alice', role: 'Dev' },
  { id: 2, nom: 'Bob',   role: 'Designer' },
];

function ListeUtilisateurs() {
  return (
    <div>
      {utilisateurs.map(u => (
        <div key={u.id}>
          <strong>{u.nom}</strong> — {u.role}
        </div>
      ))}
    </div>
  );
}

🔑 La prop key

La key est une prop spéciale que React utilise pour identifier de manière unique chaque élément d'une liste. Elle permet à React de savoir quels éléments ont changé, ont été ajoutés ou supprimés.

// ❌ Sans key — React ne peut pas optimiser les mises à jour
{items.map(item => <Item item={item} />)}

// ❌ Index comme key — problématique si la liste est réordonnée
{items.map((item, i) => <Item key={i} item={item} />)}

// ✅ ID unique stable
{items.map(item => <Item key={item.id} item={item} />)}

// ✅ Valeur unique si pas d'ID
{fruits.map(fruit => <li key={fruit}>{fruit}</li>)}
⚠️ Ne jamais utiliser l'index comme key si les éléments peuvent être réordonnés, ajoutés ou supprimés — cela cause des bugs de rendu difficiles à trouver.

🔍 Filtrer et trier

function ListeProduits({ produits }) {
  const [recherche, setRecherche] = useState('');
  const [tri, setTri] = useState('nom'); // 'nom' | 'prix'

  // Filtrer
  const filtres = produits.filter(p =>
    p.nom.toLowerCase().includes(recherche.toLowerCase())
  );

  // Trier (sans muter le tableau)
  const tries = [...filtres].sort((a, b) => {
    if (tri === 'prix') return a.prix - b.prix;
    return a.nom.localeCompare(b.nom);
  });

  return (
    <div>
      <input value={recherche} onChange={e => setRecherche(e.target.value)} placeholder="Rechercher..." />
      <select value={tri} onChange={e => setTri(e.target.value)}>
        <option value="nom">Trier par nom</option>
        <option value="prix">Trier par prix</option>
      </select>
      {tries.map(p => <ProduitCard key={p.id} produit={p} />)}
    </div>
  );
}

✏️ Listes dynamiques

function ListeDynamique() {
  const [items, setItems] = useState([
    { id: 1, texte: 'Premier', done: false },
    { id: 2, texte: 'Deuxième', done: true },
  ]);

  // Ajouter
  function ajouter(texte) {
    setItems(prev => [...prev, { id: Date.now(), texte, done: false }]);
  }

  // Modifier (toggle)
  function toggleDone(id) {
    setItems(prev =>
      prev.map(item => item.id === id ? { ...item, done: !item.done } : item)
    );
  }

  // Supprimer
  function supprimer(id) {
    setItems(prev => prev.filter(item => item.id !== id));
  }

  // Réordonner (monter)
  function monter(id) {
    setItems(prev => {
      const idx = prev.findIndex(i => i.id === id);
      if (idx === 0) return prev;
      const nouveau = [...prev];
      [nouveau[idx - 1], nouveau[idx]] = [nouveau[idx], nouveau[idx - 1]];
      return nouveau;
    });
  }
}
📝 Exercices R06 ▶ Mini-projet : Product Catalog 🧠 QCM R06 Suivant : Context →