React15 de lecture5 octobre 2024
Guide ultime : optimiser les performances React
Techniques avancées pour optimiser vos applications React : memo, useMemo, useCallback, virtualization et plus encore. Avec des benchmarks réels.
Introduction
La performance est cruciale pour l'expérience utilisateur. Une application lente perd des utilisateurs. Voici les techniques pour garder votre app React rapide comme l'éclair.
Comprendre les re-renders
Pourquoi un composant re-render ?
- Son state change
- Ses props changent
- Son parent re-render
- Le context qu'il consomme change
Identifier les re-renders
// En développement
import { Profiler } from 'react'
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) {
console.log({ id, phase, actualDuration })
}
<Profiler id="MyComponent" onRender={onRenderCallback}>
<MyComponent />
</Profiler>
Mémoisation : les bases
React.memo
Évite les re-renders si les props n'ont pas changé :
// ❌ Re-render à chaque fois que le parent re-render
function ExpensiveList({ items }) {
return items.map(item => <ExpensiveItem key={item.id} {...item} />)
}
// ✅ Re-render seulement si items change
const ExpensiveList = memo(function ExpensiveList({ items }) {
return items.map(item => <ExpensiveItem key={item.id} {...item} />)
})
useMemo
Mémorise le résultat d'un calcul coûteux :
function Dashboard({ transactions }) {
// ❌ Recalculé à chaque render
const stats = calculateStats(transactions)
// ✅ Recalculé seulement si transactions change
const stats = useMemo(
() => calculateStats(transactions),
[transactions]
)
return <StatsDisplay stats={stats} />
}
useCallback
Mémorise une fonction :
function Parent() {
const [count, setCount] = useState(0)
// ❌ Nouvelle fonction à chaque render
const handleClick = () => {
console.log('clicked')
}
// ✅ Même référence entre les renders
const handleClick = useCallback(() => {
console.log('clicked')
}, [])
return <MemoizedChild onClick={handleClick} />
}
Optimisations avancées
1. Virtualization pour les longues listes
import { useVirtual } from '@tanstack/react-virtual'
function VirtualList({ items }) {
const parentRef = useRef(null)
const virtualizer = useVirtual({
size: items.length,
parentRef,
estimateSize: useCallback(() => 50, []),
})
return (
<div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
<div style={{ height: virtualizer.totalSize }}>
{virtualizer.virtualItems.map((virtualRow) => (
<div
key={virtualRow.index}
style={{
position: 'absolute',
top: virtualRow.start,
height: virtualRow.size,
}}
>
{items[virtualRow.index].name}
</div>
))}
</div>
</div>
)
}
2. Code splitting avec lazy
import { lazy, Suspense } from 'react'
// Chargé à la demande
const HeavyChart = lazy(() => import('./HeavyChart'))
const AdminPanel = lazy(() => import('./AdminPanel'))
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/chart" element={<HeavyChart />} />
<Route path="/admin" element={<AdminPanel />} />
</Routes>
</Suspense>
)
}
3. Debounce pour les inputs
import { useDeferredValue, useState } from 'react'
function Search() {
const [query, setQuery] = useState('')
const deferredQuery = useDeferredValue(query)
return (
<>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
{/* Les résultats utilisent la valeur différée */}
<SearchResults query={deferredQuery} />
</>
)
}
4. Optimiser le Context
// ❌ Tout re-render quand n'importe quelle valeur change
const AppContext = createContext({ user: null, theme: 'light', /* ... */ })
// ✅ Séparer les contexts par domaine
const UserContext = createContext(null)
const ThemeContext = createContext('light')
// ✅ Mémoiser la value du provider
function UserProvider({ children }) {
const [user, setUser] = useState(null)
const value = useMemo(
() => ({ user, setUser }),
[user]
)
return (
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
)
}
Mesurer les performances
Web Vitals
import { getCLS, getFID, getLCP } from 'web-vitals'
getCLS(console.log) // Cumulative Layout Shift
getFID(console.log) // First Input Delay
getLCP(console.log) // Largest Contentful Paint
Chrome DevTools
- Performance tab : Enregistrez et analysez le timeline
- React DevTools Profiler : Identifiez les composants lents
- Lighthouse : Audit complet des performances
Checklist de performance
- Utiliser React.memo pour les composants purs
- Virtualiser les listes de plus de 100 éléments
- Lazy load les routes et composants lourds
- Optimiser les images (next/image, srcset)
- Éviter les inline objects/functions dans JSX
- Séparer les contexts par domaine
- Utiliser useDeferredValue pour les inputs
- Profiler régulièrement en production
Conclusion
L'optimisation des performances React est un processus continu. Mesurez d'abord, optimisez ensuite. N'optimisez pas prématurément, mais gardez ces techniques en tête lors du développement.
#React#Performance#Optimization
Partager cet article