Intermédiaire

L'Écosystème React

React n'est pas un framework monolithique : c'est une bibliothèque de composants UI. Tout le reste — routing, formulaires, fetching, animations, graphiques — repose sur un écosystème de librairies maintenues par la communauté.

La bonne nouvelle ? Vous n'avez pas à tout réinventer. Pour chaque problème courant, il existe probablement une librairie battle-tested, utilisée en production par des milliers d'entreprises.

La philosophie React

React encourage la composabilité : assemblez les bonnes briques plutôt que de tout construire vous-même. Choisir la bonne librairie pour le bon problème est une compétence essentielle du développeur React.

Les outils que vous connaissez déjà — et leurs alternatives

Vous avez déjà utilisé plusieurs outils dans ce cours. Voyons où ils se situent dans l'écosystème et quelles alternatives existent.

Build tool : Vite

Vous utilisez Vite pour créer et bundler vos projets React. C'est le standard actuel pour les nouveaux projets.

OutilDescriptionStatut
ViteBuild tool ultra-rapide, HMR instantané✅ Recommandé
Create React AppAncien outil officiel de Meta❌ Déprécié (2023)
Next.jsFramework fullstack (SSR, SSG, API routes)✅ Pour les projets fullstack
RemixFramework fullstack axé sur les standards web✅ Alternative à Next.js

Vite vs Next.js

Vite est parfait pour les SPA (Single Page Applications) comme celles que vous construisez en cours.

Next.js est le choix quand vous avez besoin de Server-Side Rendering (SSR), de Static Site Generation (SSG), ou d'API routes intégrées. C'est le framework recommandé par l'équipe React elle-même pour les nouveaux projets en production.

Routing : React Router DOM

Vous utilisez React Router DOM pour la navigation. C'est la librairie de routing la plus populaire.

OutilDescriptionPoints forts
React Router DOMStandard de facto, mature✅ Énorme communauté, bien documenté
TanStack RouterNouvelle génération, 100% type-safe✅ Typage complet, recherche type-safe
tsx
// React Router DOM (ce que vous connaissez)
<Route path="/users/:id" element={<UserPage />} />

// TanStack Router (alternative type-safe)
const userRoute = createRoute({
  path: '/users/$id',
  component: UserPage,
  validateSearch: z.object({ tab: z.string().optional() }),
})

Validation : Zod

Vous utilisez Zod pour la validation. Voici les alternatives :

OutilDescriptionPoints forts
ZodValidation type-safe, standard moderne✅ Inférence TypeScript, zero-dependency
YupHistoriquement populaireBon écosystème, moins type-safe
ValibotUltra-léger, tree-shakable✅ ~1kb vs ~8kb pour Zod

Valibot : l'alternative légère

Valibot est une alternative récente à Zod avec une API similaire mais un bundle beaucoup plus petit grâce au tree-shaking. Si la taille du bundle est critique pour votre projet, Valibot mérite un coup d'œil.

tsx
// Zod
import { z } from 'zod';
const schema = z.object({ name: z.string().min(3) });

// Valibot (API similaire, bundle plus petit)
import * as v from 'valibot';
const schema = v.object({ name: v.pipe(v.string(), v.minLength(3)) });

Pourquoi Next.js est-il recommandé pour les projets en production plutôt que Vite seul ?

Gestion des formulaires — React Hook Form

Le problème

Vous avez appris à créer des formulaires avec useState. Ça fonctionne, mais sur des formulaires complexes (10+ champs), ça devient verbeux et chaque frappe clavier provoque un re-render du composant entier.

tsx
// ❌ Avec useState : verbeux et re-renders à chaque frappe
function SignupForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [age, setAge] = useState('');
  // ... un useState par champ, ça s'accumule vite !
}

La solution : React Hook Form

React Hook Form utilise des refs au lieu de state, ce qui évite les re-renders inutiles. Il s'intègre parfaitement avec Zod via @hookform/resolvers.

bash
npm install react-hook-form @hookform/resolvers
tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  name: z.string().min(2, 'Au moins 2 caractères'),
  email: z.string().email('Email invalide'),
  age: z.number().min(18, 'Minimum 18 ans'),
});

type FormData = z.infer<typeof schema>;

function SignupForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  const onSubmit = (data: FormData) => {
    console.log('Données validées :', data); // Type-safe !
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} placeholder="Nom" />
      {errors.name && <span>{errors.name.message}</span>}

      <input {...register('email')} placeholder="Email" />
      {errors.email && <span>{errors.email.message}</span>}

      <input {...register('age', { valueAsNumber: true })} placeholder="Age" type="number" />
      {errors.age && <span>{errors.age.message}</span>}

      <button type="submit">S'inscrire</button>
    </form>
  );
}

React Hook Form + Zod = le combo parfait

  • React Hook Form gère les formulaires (performance, soumission, états)
  • Zod gère la validation (règles, types, messages d'erreur)
  • register('name') retourne les props onChange, onBlur, ref — pas besoin de useState !

Data Fetching — TanStack Query

Le problème

Vous avez appris à fetch des données avec useEffect + useState. Ce pattern fonctionne, mais il manque beaucoup de choses : cache, refetch automatique, invalidation, gestion d'erreur avancée...

tsx
// ❌ Le pattern classique : répétitif et sans cache
function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(data => setUsers(data))
      .catch(err => setError(err))
      .finally(() => setLoading(false));
  }, []);

  // ... gérer loading, error, data à chaque fois
}

La solution : TanStack Query

TanStack Query (anciennement React Query) gère tout ça automatiquement : cache, refetch, loading/error states, pagination, et plus encore.

bash
npm install @tanstack/react-query
tsx
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

// Lire des données
function UserList() {
  const { data: users, isLoading, error } = useQuery({
    queryKey: ['users'],
    queryFn: () => fetch('/api/users').then(res => res.json()),
  });

  if (isLoading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

// Écrire des données (POST, PUT, DELETE)
function CreateUser() {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (newUser) => fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(newUser),
    }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] }); // Rafraîchit la liste !
    },
  });

  return <button onClick={() => mutation.mutate({ name: 'Alice' })}>Ajouter</button>;
}

Pourquoi TanStack Query ?

  • Cache automatique : les données ne sont pas re-fetchées inutilement
  • Refetch intelligent : au focus de la fenêtre, à la reconnexion réseau
  • Invalidation : quand vous modifiez des données, les listes se mettent à jour
  • Loading/Error/Success : gérés automatiquement
  • DevTools : un panneau pour inspecter le cache en temps réel

Quel est l'avantage principal de TanStack Query par rapport au pattern useEffect + fetch ?

Visualisation de données — Recharts

Quand vous devez afficher des graphiques (barres, lignes, camemberts...), inutile de dessiner du SVG à la main. Recharts est la librairie la plus populaire pour les graphiques en React.

bash
npm install recharts
tsx
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';

const data = [
  { mois: 'Jan', ventes: 400 },
  { mois: 'Fev', ventes: 300 },
  { mois: 'Mar', ventes: 600 },
  { mois: 'Avr', ventes: 800 },
  { mois: 'Mai', ventes: 500 },
];

function SalesChart() {
  return (
    <LineChart width={600} height={300} data={data}>
      <CartesianGrid strokeDasharray="3 3" />
      <XAxis dataKey="mois" />
      <YAxis />
      <Tooltip />
      <Line type="monotone" dataKey="ventes" stroke="#8884d8" strokeWidth={2} />
    </LineChart>
  );
}

Alternatives à Recharts

  • Chart.js (via react-chartjs-2) : Très populaire, nombreux types de graphiques
  • Nivo : Graphiques soignés, animé par défaut
  • Victory : API déclarative, bonne documentation
  • Tremor : Composants de dashboard pré-stylés (construit sur Recharts)

3D et Animations

React Three Fiber — La 3D dans React

React Three Fiber est un wrapper React pour Three.js, la référence en 3D sur le web. Il permet de créer des scènes 3D avec la syntaxe déclarative de React.

bash
npm install three @react-three/fiber @react-three/drei
tsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';

function RotatingCube() {
  return (
    <mesh rotation={[0.5, 0.5, 0]}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="royalblue" />
    </mesh>
  );
}

function Scene() {
  return (
    <Canvas style={{ height: '400px' }}>
      <ambientLight intensity={0.5} />
      <pointLight position={[10, 10, 10]} />
      <RotatingCube />
      <OrbitControls />
    </Canvas>
  );
}

Quand utiliser React Three Fiber ?

  • Visualisations 3D interactives
  • Configurateurs de produits (e-commerce)
  • Jeux simples dans le navigateur
  • Animations 3D avancées

Le package @react-three/drei fournit des helpers prêts à l'emploi : contrôles de caméra, textes 3D, loaders de modèles, etc.

Framer Motion — Animations déclaratives

Framer Motion permet d'animer vos composants React de manière déclarative, sans CSS complexe ni JavaScript impératif.

bash
npm install framer-motion
tsx
import { motion } from 'framer-motion';

function AnimatedCard() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
      className="card"
    >
      <h3>Je suis animée !</h3>
    </motion.div>
  );
}

Framer Motion en bref

  • initial : état de départ de l'animation
  • animate : état final
  • transition : durée, easing, délai
  • whileHover / whileTap : animations interactives
  • exit : animation de sortie (avec AnimatePresence)

Composants UI — Radix UI / shadcn/ui

Le problème des composants UI

Construire un select, un dialog, un dropdown menu ou un accordion accessibles et fonctionnels est beaucoup plus complexe qu'il n'y paraît. Il faut gérer le clavier, l'accessibilité (ARIA), le focus trapping, etc.

Headless UI : Radix UI

Radix UI fournit des composants headless (sans style) qui gèrent toute la logique et l'accessibilité. Vous ajoutez votre propre style.

tsx
import * as Dialog from '@radix-ui/react-dialog';

function MyDialog() {
  return (
    <Dialog.Root>
      <Dialog.Trigger>Ouvrir</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className="overlay" />
        <Dialog.Content className="dialog">
          <Dialog.Title>Mon Dialog</Dialog.Title>
          <Dialog.Description>Contenu accessible et fonctionnel.</Dialog.Description>
          <Dialog.Close>Fermer</Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}

shadcn/ui : le meilleur des deux mondes

shadcn/ui n'est pas une librairie traditionnelle — c'est une collection de composants que vous copiez dans votre projet. Ils sont construits sur Radix UI + Tailwind CSS.

bash
# Ajouter un composant
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add select
tsx
// Le composant est copié dans votre projet — vous le possédez !
import { Button } from '@/components/ui/button';

function MyPage() {
  return (
    <div>
      <Button variant="default">Primaire</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="destructive">Supprimer</Button>
    </div>
  );
}

Pourquoi shadcn/ui ?

  • Vous possédez le code : les composants sont dans votre projet, pas dans node_modules
  • Entièrement personnalisable : modifiez le code source directement
  • Accessible : construit sur Radix UI
  • Beau par défaut : style Tailwind CSS soigné
  • Pas de dépendance : pas de version à maintenir

Gestion d'état globale — Zustand

Le problème

La Context API de React fonctionne pour partager un état simple, mais elle a des limites :

  • Verbeux (Provider, Context, useContext)
  • Re-renders excessifs si mal utilisée
  • Pas de devtools intégrées

La solution : Zustand

Zustand (mot allemand pour "état") est une librairie de gestion d'état minimaliste et performante.

bash
npm install zustand
tsx
import { create } from 'zustand';

// Créer un store en 5 lignes
const useCartStore = create((set) => ({
  items: [],
  addItem: (item) => set((state) => ({
    items: [...state.items, item],
  })),
  removeItem: (id) => set((state) => ({
    items: state.items.filter(item => item.id !== id),
  })),
  clearCart: () => set({ items: [] }),
}));

// Utiliser dans n'importe quel composant — sans Provider !
function CartIcon() {
  const itemCount = useCartStore((state) => state.items.length);
  return <span>Panier ({itemCount})</span>;
}

function CartPage() {
  const { items, removeItem, clearCart } = useCartStore();
  return (
    <div>
      {items.map(item => (
        <div key={item.id}>
          {item.name} <button onClick={() => removeItem(item.id)}>X</button>
        </div>
      ))}
      <button onClick={clearCart}>Vider le panier</button>
    </div>
  );
}

Zustand vs Context API

Context APIZustand
SetupProvider + Context + useContextcreate() + hook
Re-rendersTous les consumers re-renderSeulement si la valeur sélectionnée change
DevToolsNonOui (middleware)
PersistanceManuelleMiddleware intégré
Courbe d'apprentissageFaibleFaible

Règle simple : Context API pour un état simple (thème, langue). Zustand pour un état complexe (panier, authentification, filtres).

Autres librairies utiles

L'écosystème React est vaste. Voici quelques librairies supplémentaires à garder en tête :

CatégorieLibrairieDescription
Datesdate-fnsManipulation de dates, léger et modulaire
Tables@tanstack/react-tableTableaux avec tri, filtre, pagination
Toast / NotificationssonnerNotifications élégantes et simples
Drag & Drop@dnd-kit/coreDrag and drop accessible et performant
Éditeurs de graphes@xyflow/react (React Flow)Éditeurs node-based interactifs (pipelines, workflows, diagrammes)
Icôneslucide-react+1000 icônes SVG en composants React
PDF@react-pdf/rendererGénérer des PDF avec des composants React
Internationalisationreact-i18nextTraduction et localisation

date-fns : l'utilitaire de dates

Ne réinventez jamais la manipulation de dates ! date-fns est léger et modulaire (vous n'importez que ce que vous utilisez).

tsx
import { format, addDays, isAfter } from 'date-fns';
import { fr } from 'date-fns/locale';

const today = new Date();
const nextWeek = addDays(today, 7);

format(today, 'dd MMMM yyyy', { locale: fr }); // "23 mars 2026"
isAfter(nextWeek, today); // true

Quelle est la différence principale entre shadcn/ui et une librairie de composants classique comme Material UI ?

Comment choisir une librairie ?

Face à un nouveau besoin, ne codez pas tout de zéro. Mais ne choisissez pas non plus la première librairie venue. Voici comment évaluer :

Les critères essentiels

  1. Popularité et maintenance

    • Nombre de stars GitHub et de téléchargements npm hebdomadaires
    • Date du dernier commit (la librairie est-elle activement maintenue ?)
    • Nombre d'issues ouvertes et de contributeurs
  2. Taille du bundle

    • Vérifiez sur bundlephobia.com la taille ajoutée à votre projet
    • Une librairie de 200kb pour un problème simple ? Probablement excessif.
  3. Qualité de la documentation

    • Exemples clairs et à jour ?
    • Guide de démarrage rapide ?
    • Documentation de l'API complète ?
  4. Compatibilité

    • Supporte TypeScript ?
    • Compatible avec votre version de React ?
    • Fonctionne avec vos autres outils (Vite, Tailwind, etc.) ?

Les outils pour comparer

# Comparer les tendances de téléchargement
https://npmtrends.com/zustand-vs-jotai-vs-recoil

# Vérifier la taille d'un package
https://bundlephobia.com/package/zustand

# Explorer l'écosystème
https://github.com/enaqx/awesome-react

Le test des 50 lignes

Ai-je vraiment besoin d'une librairie ?

Avant d'installer une dépendance, posez-vous la question :

"Est-ce que je peux coder ça moi-même en moins de 50 lignes ?"

  • Oui → Codez-le vous-même (fonction de formatage simple, petit hook utilitaire)
  • Non → Utilisez une librairie battle-tested (formulaires, graphiques, 3D, drag & drop)

Par exemple :

  • Formater une date en JJ/MM/AAAA ? Vous pouvez le faire en quelques lignes.
  • Gérer un formulaire complexe avec validation, erreurs par champ et performance ? Utilisez React Hook Form + Zod.
  • Créer un graphique interactif ? Utilisez Recharts.

Récapitulatif

Ce que vous avez découvert

L'écosystème React — les bonnes briques pour chaque problème :

  1. Build : Vite (SPA) ou Next.js (fullstack/SSR)
  2. Routing : React Router DOM ou TanStack Router (type-safe)
  3. Validation : Zod, Yup, ou Valibot
  4. Formulaires : React Hook Form + Zod = combo parfait
  5. Data Fetching : TanStack Query (cache, refetch, invalidation)
  6. Graphiques : Recharts, Chart.js, Nivo
  7. 3D : React Three Fiber
  8. Animations : Framer Motion
  9. Composants UI : shadcn/ui (Radix + Tailwind)
  10. État global : Zustand

La démarche à retenir :

  • ✅ Cherchez si une librairie existe avant de coder from scratch
  • ✅ Évaluez : popularité, taille, docs, maintenance
  • ✅ Utilisez le test des 50 lignes
  • ✅ Lisez la documentation officielle
  • ❌ N'installez pas une librairie de 200kb pour un problème de 10 lignes