Tutoriel React — Chapitre 20

Mini-projet complet (mise en pratique)

Chapitre 20 — Mini-projet complet (mise en pratique)

À ce stade, vous savez créer des composants, gérer le state, faire des effets, router, etc. La différence entre un projet “qui marche” et un projet “pro” tient souvent à la structure et aux patterns (schémas de conception) utilisés. Dans ce chapitre, on pose des règles simples, très utiles pour progresser rapidement.

Objectif : comprendre (pas apprendre par cœur) Niveau : débutant absolu Pratique : mini-exercice à la fin

Plan du chapitre

1) Nommage et lisibilité

En React, vous lisez du code plus que vous n’en écrivez. Le nommage est donc capital.

  • Composants : PascalCase (UserCard, ProductList)
  • Fonctions : camelCase (handleSubmit, toggleTheme)
  • Handlers : préfixe handle ou on (ex : onDelete)
  • Booleans : commence souvent par is, has, can
const [isOpen, setIsOpen] = useState(false);
const [hasError, setHasError] = useState(false);

function handleOpen() { setIsOpen(true); }

2) Découper en composants : règle simple

Si un composant dépasse ~150 lignes et mélange beaucoup de responsabilités, c’est souvent un signe qu’il faut découper.

Règle pratique

  • Un composant = une idée principale
  • La page assemble des composants
  • Le composant enfant se concentre sur un rôle précis (afficher, saisir, etc.)

Exemple : une page “Users” assemble : SearchBar, UserList, UserCard.

3) Composition : “assembler” plutôt que dupliquer

En React, on évite de copier-coller des blocs. On préfère créer des composants réutilisables et les assembler.

Exemple : un composant Card réutilisable

export default function Card({ title, children }) {
  return (
    <section className="card">
      <h3>{title}</h3>
      <div>{children}</div>
    </section>
  );
}

Utilisation

<Card title="Profil">
  <p>Nom : Ahmed</p>
</Card>

<Card title="Réglages">
  <button>Activer les notifications</button>
</Card>

Le pattern children est l’un des plus importants en React : vous “injectez” du contenu.

4) Lifting state up : remonter le state au bon niveau

Problème classique : deux composants frères doivent partager une information. Exemple : une barre de recherche et une liste filtrée. Si chacun garde son state dans son coin, ils ne peuvent pas se synchroniser.

Solution : on “remonte” le state dans le parent commun, puis on redescend :

  • le state en props
  • les setters/fonctions en props
UsersPage
├─ SearchBar (met à jour search)
└─ UserList (utilise search)

Exemple minimal

function UsersPage({ users }) {
  const [search, setSearch] = useState("");

  const filtered = users.filter((u) =>
    u.name.toLowerCase().includes(search.toLowerCase())
  );

  return (
    <div>
      <SearchBar value={search} onChange={setSearch} />
      <UserList users={filtered} />
    </div>
  );
}

Remonter le state au bon niveau est une compétence essentielle pour structurer une app.

5) Composants contrôlés vs non contrôlés

Vous connaissez déjà les champs contrôlés (value vient du state). Il existe aussi des champs “non contrôlés” via les refs.

A) Contrôlé (recommandé pour débuter)

const [email, setEmail] = useState("");
<input value={email} onChange={(e) => setEmail(e.target.value)} />

B) Non contrôlé (avec useRef)

const inputRef = useRef(null);

const handleSubmit = (e) => {
  e.preventDefault();
  console.log(inputRef.current.value);
};

<input ref={inputRef} />

Le non contrôlé est utile dans certains cas (performance, intégration libs externes), mais pour apprendre, restez sur le contrôlé.

6) Organisation des dossiers

Une structure simple, claire et adaptée à la majorité des projets :

src/
├─ App.jsx
├─ main.jsx
├─ pages/
├─ components/
├─ layouts/
├─ contexts/
├─ hooks/
├─ services/
└─ assets/
  • pages/ : pages routées
  • components/ : UI réutilisable
  • services/ : appels API (fetch), helpers
  • hooks/ : hooks custom
  • contexts/ : Context API

7) Anti-patterns courants (débutants)

Mettre trop de logique dans un seul composant “page”

Découpez : UI (components) + logique (hooks/services) + page (assemblage).

Utiliser le state alors qu’un simple calcul suffit

Si une valeur peut être calculée à partir d’autres states/props, calculez-la dans le rendu (ou useMemo si nécessaire) au lieu de stocker un “double state”.

Dupliquer le même code (copier-coller)

Transformez en composant (ou en fonction utilitaire) et réutilisez.

Gérer des side effects au mauvais endroit

Les side effects (fetch, timer, subscription) vont dans useEffect, pas dans le rendu, ni dans un reducer.

8) Résumé (à retenir)

  • Découpez : un composant = un rôle principal.
  • Préférez la composition à la duplication (children).
  • Remontez le state au bon niveau (lifting state up).
  • Structurez vos dossiers : pages / components / services / hooks / contexts.
  • Ne stockez pas dans le state ce qui peut être calculé.

9) Exercice pratique

Objectif : appliquer la composition et le lifting state up sur un mini-projet.

Consigne

  • Créez une page ProductsPage avec une liste de produits (tableau en dur).
  • Ajoutez une barre de recherche SearchBar (input contrôlé).
  • Filtrez les produits dans la page (state remonte au parent).
  • Affichez les produits via ProductList et ProductCard.
  • Créez un composant Card réutilisable avec children.

Bonus

Ajoutez un tri (prix croissant/décroissant) en gardant une structure propre (state au bon endroit).

Prochaine étape : Chapitre 21 — Hooks personnalisés : créer vos propres hooks (useLocalStorage, useFetch, etc.).