Publie le 24 mars 2026 Par

Performances React : memo, useMemo, useCallback, virtualisation — guide pratique

Les performances React sont souvent optimisées prématurément — ou pas du tout. Les développeurs juniors appliquent useMemo et useCallback partout par précaution, ou ignorent les problèmes de performance jusqu’à ce que l’application rame. Ce guide vous donne une méthode pour mesurer d’abord, puis optimiser au bon endroit.

La règle d’or : mesurer avant d’optimiser

React est rapide par défaut. Un composant qui se re-rend inutilement n’est pas forcément un problème si le rendu est rapide. Avant d’ajouter useMemo ou React.memo, profilez avec React DevTools Profiler pour identifier les composants qui causent réellement des problèmes de performance.

Ce que vous cherchez dans le Profiler : les composants avec des temps de rendu élevés (> 16ms) ou qui se re-rendent très fréquemment sans raison.

React.memo — éviter les re-renders inutiles

Par défaut, quand un composant parent se re-rend, tous ses enfants se re-rendent aussi — même si leurs props n’ont pas changé. React.memo mémoïse un composant et le re-rend uniquement si ses props changent.

// Sans memo : se re-rend à chaque render du parent
function ExpensiveChild({ data }: { data: Data }) {
  return 
{/* calcul lourd */}
} // Avec memo : se re-rend seulement si data change const ExpensiveChild = React.memo(function ExpensiveChild({ data }: { data: Data }) { return
{/* calcul lourd */}
}) // ⚠️ Piège : si data est un objet créé inline dans le parent, // la référence change à chaque render → memo ne sert à rien function Parent() { // ❌ Nouvel objet à chaque render → ExpensiveChild se re-rend toujours return // ✅ Mémoïser l'objet dans le parent const data = useMemo(() => ({ value: 42 }), []) return }

useMemo — mémoïser des calculs coûteux

// Utile quand : calcul coûteux qui dépend de données qui changent rarement
const sortedAndFilteredItems = useMemo(() => {
  return items
    .filter(item => item.category === selectedCategory)
    .sort((a, b) => a.price - b.price)
}, [items, selectedCategory])

// Inutile quand : le calcul est trivial
// ❌ Sur-utilisation — le coût de useMemo dépasse le bénéfice
const doubledValue = useMemo(() => value * 2, [value])
// ✅ Juste
const doubledValue = value * 2

useCallback — mémoïser des fonctions

// ❌ Nouvelle référence à chaque render — React.memo sur l'enfant ne fonctionne pas
function Parent() {
  const handleClick = () => doSomething(userId) // nouvelle fonction à chaque render
  return 
}

// ✅ Référence stable — MemoizedChild ne se re-rend pas si userId n'a pas changé
function Parent() {
  const handleClick = useCallback(() => doSomething(userId), [userId])
  return 
}

// useCallback vaut la peine quand :
// 1. La fonction est passée à un composant mémoïsé (React.memo)
// 2. La fonction est une dépendance d'un useEffect
// Dans les autres cas, c'est souvent inutile

Virtualisation — les longues listes

Le vrai problème de performance avec les listes : rendre 10 000 éléments dans le DOM, même vides. La virtualisation ne rend que les éléments visibles à l’écran.

// TanStack Virtual (anciennement react-virtual)
import { useVirtualizer } from '@tanstack/react-virtual'

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef(null)

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50, // hauteur estimée d'un élément
  })

  return (
    
{virtualizer.getVirtualItems().map(virtualItem => (
{items[virtualItem.index].name}
))}
) }

Le lazy loading des composants

// Charger un composant lourd seulement quand il est nécessaire
const HeavyChart = lazy(() => import('./HeavyChart'))

function Dashboard() {
  const [showChart, setShowChart] = useState(false)

  return (
    
{showChart && ( Chargement...
}> )}
) }

Les causes réelles de lenteur en React

En pratique, les problèmes de performance React viennent rarement des re-renders. Les vraies causes :

  • Trop de données dans le DOM → virtualisation
  • Images non optimisées → next/image ou lazy loading natif
  • Requêtes réseau trop nombreuses ou trop lentes → cache avec React Query
  • Bundle JavaScript trop lourd → code splitting avec lazy()
  • State global qui trigger des re-renders en cascade → Zustand avec selectors granulaires

Offres développeur React

Des postes pour développeurs React qui savent optimiser et profileur leurs applications.

À lire aussi : Hooks ReactState management ReactNext.js pour débutant

Categories : JavaScript & React