• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • GitLab
      • Plateforme monday.com
      • Scaleway
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
    • 🤖 L’IA au service de vos projets numériques
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Ouicommit Paris – IA : de l’expérimentation à l’industrialisation
Ouicommit Paris – IA : de l’expérimentation à l’industrialisation
15 avril 2026
Ressources > Articles techniques > Diagnostiquer, comprendre et optimiser les performances d’une application React

Diagnostiquer, comprendre et optimiser les performances d’une application React

Écrit par Thomas M.

Diagnostiquer, comprendre et optimiser les performances d’une application React

Une application React “lente” ne se résume pas à “React est lourd”. Dans la majorité des cas, les problèmes viennent de re-renders inutiles, d’un DOM trop volumineux ou d’un bundle surdimensionné. L’objectif de cet article est de donner une démarche concrète et des techniques pratiques pour diagnostiquer et optimiser les performances de vos composants.

Comprendre d’où viennent les lenteurs

Chaque mise à jour en React passe par le cycle render → reconciliation → commit : React exécute le composant, compare le virtual DOM avec le précédent puis applique les changements au DOM. Un re-render peut venir d’un setState, d’un changement de props, de context, ou simplement d’un parent qui se rafraîchit.

Les ralentissements proviennent souvent de re-renders inutiles, notamment lorsque :

  • Un composant se re-render alors que ses props n’ont pas changé,
  • Des callbacks ou objets sont recréés à chaque render (() => …, style={{…}}),
  • Un state ou un contexte trop global force une grande partie de l’arbre à se mettre à jour.

Identifier ces situations permet de cibler précisément ce qu’il faut optimiser avant d’appliquer React.memo, useCallback ou useMemo.

Profiler l’application pour mesurer avant d’optimiser

  • Le React DevTools Profiler est l’outil principal pour analyser les re-renders.
    Il permet d’enregistrer une interaction et d’inspecter :
    • Le Flamegraph : visualise les composants les plus coûteux (barres larges ou colorées).
    • La vue Ranked : classe les composants du plus lent au plus rapide.
    • “Why did this render?” : indique la raison exacte d’un re-render (props changed, parent rendered, etc.).

Exemple classique : une simple frappe dans un champ de recherche rafraîchit un Header statique → signe d’un re-render inutile.

  • Quand l’UI freeze malgré des renders React rapides, utilisez l’onglet Performance de Chrome pour repérer des Long Tasks (>50 ms) sur le thread principal. On y détecte souvent des :
    • Calculs JavaScript lourds,
    • Recalculs de layout,
    • Phases de garbage collection.

Croiser les données des deux outils permet de savoir si le problème vient réellement de React ou d’un coût externe (algorithme, librairie, manipulation du DOM).

Limiter les re-renders avec React.memo, useMemo, useCallback

React.memo : limiter le render d’un composant

React.memo mémorise le render d’un composant fonctionnel basé sur une comparaison superficielle de ses props.

const Header = React.memo(function Header({ user }) {
  return <h1>Bonjour {user.name}</h1>;
});

Si user (référence) ne change pas, Header ne se re-render pas, même si son parent s’actualise.

Attention : si vous passez un objet ou une fonction recréés à chaque render (onClick={() => …}, style={{ ... }}), la comparaison échoue et React.memo ne sert plus à rien.

React.memo effectue une comparaison superficielle (shallow compare) des props à chaque render du parent.
Cette comparaison a elle-même un coût, proportionnel au nombre de props. Sur des composants simples ou peu coûteux à rendre, ce coût peut être supérieur au gain, rendant React.memo inutile voire contre-productif.

useMemo : Mémoïser les calculs et stabiliser les objets

Deux grands cas d’usage :

  1. Calculs coûteux
const filteredTodos = useMemo(
  () => todos.filter(t => t.text.includes(filter)),
  [todos, filter]
);

Le filtre n’est recalculé que si todos ou filter change réellement.

  1. Stabiliser des props non primitives
const style = useMemo(
  () => ({ backgroundColor: theme === 'dark' ? 'black' : 'white' }),
  [theme]
);
// sans useMemo, un nouveau `{}` à chaque render casse React.memo
<MemoizedChild style={style} />;

useCallback : Stabiliser les fonctions passées en props

useCallback est l’équivalent de useMemo pour les fonctions :

const handleClick = useCallback(() => {
  alert('Clic !');
}, []); 
<MemoizedButton onClick={handleClick} />;

Indispensable dès que :

  • Vous passez un callback à un composant mémoïsé,
  • Vous utilisez une fonction dans les dépendances d’un useEffect.

Colocaliser l’état et structurer l’architecture

Une des optimisations les plus simples mais tout autant efficace est de déplacer l’état aussi bas que possible.

Dans cet exemple, le composant App re-render tout à chaque saisie.

function App() {
  const [text, setText] = useState('');
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <HeavyChart />
      <ExpensiveTable />
    </>
  );
}

Déplacer l’état dans un composant → la saisie ne re-render que le petit composant.

function SearchInput() {
  const [text, setText] = useState('');
  return <input value={text} onChange={e => setText(e.target.value)} />;
}
function App() {
  return (
    <>
      <SearchInput />
      <HeavyChart />
      <ExpensiveTable />
    </>
  );
}

Dans vos formulaires, listes et dashboards :

  • Séparez les états qui changent souvent (input, filtres) de ceux qui changent rarement,
  • Découpez en petits composants pour limiter la zone impactée par chaque mise à jour.

Virtualiser Les listes longues

Le problème du DOM trop volumineux

Render une liste de 10 000 éléments avec un simple .map() crée 10 000 nœuds DOM. Conséquences :

  • Temps de render initial énorme,
  • Scroll saccadé,
  • Re-renders catastrophiques,
  • Risque de crash de l’onglet.

Virtualisation

La virtualisation permet de ne render que les éléments visibles à l’écran + un petit buffer. Bibliothèques courantes :

  • TanStack Virtual (@tanstack/react-virtual),
  • react-window.

Exemple simplifié avec TanStack Virtual :

import { useVirtualizer } from '@tanstack/react-virtual';
function VirtualizedList({ items }) {
  const parentRef = useRef(null);
  const rowVirtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 35,
  });
  return (
    <div ref={parentRef} style={{ height: 400, overflow: 'auto' }}>
      <div
        style={{
          height: rowVirtualizer.getTotalSize(),
          position: 'relative',
          width: '100%',
        }}
      >
        {rowVirtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.key}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: virtualRow.size,
              transform: `translateY(${virtualRow.start}px)`,
            }}
          >
            {items[virtualRow.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

Pour les hauteurs dynamiques, on peut mesurer chaque élément après le render et laisser la lib ajuster la position et la hauteur totale.

Optimiser le chargement et le bundle

Réduire le temps du premier chargement est tout aussi important que d’accélérer les renders.

Code splitting avec React.lazy et Suspense

Une première approche consiste à utiliser le code splitting grâce à React.lazy et Suspense. Cela permet de ne charger certaines parties qu’au moment où elles sont nécessaires, par exemple une page lourde ou une fonctionnalité secondaire.

const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
<Suspense fallback={<div>Chargement...</div>}>
  <Routes>
    <Route path="/dashboard" element={<DashboardPage />} />
  </Routes>
</Suspense>

React.lazy est particulièrement utile au niveau des routes, mais aussi pour des composants rarement affichés (éditeur riche, graphiques, modales complexes).

Lazy loading des librairies lourdes

Il est également important de pratiquer le lazy loading des librairies lourdes, en utilisant les imports dynamiques (import()). Cela évite de charger des outils coûteux tant que l’utilisateur n’en a pas besoin.

Analyse de bundle

Pour comprendre ce qui alourdit réellement l’application, il faut analyser le bundle à l’aide d’outils comme webpack-bundle-analyzer ou rollup-plugin-visualizer. Cela permet d’identifier facilement :

  • Les dépendances trop volumineuses,
  • Les doublons,
  • Ou les imports non ciblés (ex. importer toute une bibliothèque alors qu’une seule fonction est utilisée).

Optimisation des images

Enfin, les images peuvent fortement dégrader le chargement si elles sont mal optimisées. Utiliser des formats modernes comme WebP ou AVIF, combiner cela avec loading="lazy" et ajuster la taille des fichiers permet d’obtenir un gain de performance immédiat.

Lorsque les optimisations classiques ne suffisent pas, il existe des méthodes plus avancées en fonction des cas d’utilisations.

Appliquer des techniques avancées

Quand les optimisations “classiques” ne suffisent pas :

  • useTransition et useDeferredValue : marquer certaines mises à jour comme non urgentes pour éviter les freezes lors de filtres complexes ou de gros changements d’écran. (React 18+)
  • Render concurrent : permet à React d’interrompre un render long pour traiter une interaction plus urgente (frappe clavier, clic).
  • Web Workers : déporter les calculs CPU lourds (algos, parsing) hors du thread principal.
  • <canvas> / WebGL : pour les interfaces à très haute fréquence de rafraîchissement (graphiques temps réel, visualisations interactives).

Conclusion

Optimiser les performances d’une application React, ce n’est pas tout envelopper dans React.memo.

  • Mesurer avec React DevTools et le Performance Profiler.
  • Identifier les re-renders inutiles et les composants réellement coûteux.
  • Optimiser localement avec React.memo, useMemo, useCallback et une bonne colocation de l’état.
  • Traiter les cas extrêmes (listes longues, bundles volumineux) avec la virtualisation et le code splitting.
  • Répéter le cycle mesure → optimisation → mesure.

En gardant cette démarche scientifique, vous évitez l’optimisation prématurée tout en construisant des applications React rapides, fluides et maintenables.

À lire aussi

Ouicommit Paris – IA : de l’expérimentation à l’industrialisation
15 avril 2026

Ouicommit Paris – IA : de l’expérimentation à l’industrialisation

Lire la suite de l'article

Ouidou et Scaleway : un partenariat stratégique pour accélérer le cloud souverain en Europe
8 avril 2026

Ouidou et Scaleway : un partenariat stratégique pour accélérer le cloud souverain en Europe

Lire la suite de l'article

JTE : un moteur de templates moderne, rapide et sécurisé pour Java
9 mars 2026

JTE : un moteur de templates moderne, rapide et sécurisé pour Java

Lire la suite de l'article

La Sobriété Numérique, de la quantification des émissions carbone des applications à la mise en œuvre des corrections
16 février 2026

La Sobriété Numérique, de la quantification des émissions carbone des applications à la mise en œuvre des corrections

Lire la suite de l'article

Articles associés

Diagnostiquer, comprendre et optimiser les performances d’une application React
4 mai 2026

Diagnostiquer, comprendre et optimiser les performances d’une application React


Lire la suite
JTE : un moteur de templates moderne, rapide et sécurisé pour Java
9 mars 2026

JTE : un moteur de templates moderne, rapide et sécurisé pour Java


Lire la suite
Introduction pratique au Q-learning avec Gymnasium Taxi-v3
6 janvier 2026

Introduction pratique au Q-learning avec Gymnasium Taxi-v3


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou
logo ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter