0 XP
?
Avancé55 min45 XP

Objectifs de cette leçon

  • Optimiser les rendus React Native
  • Utiliser les hooks de performance
  • Profiler et résoudre les goulots d'étranglement

Performance en React Native ⚡

Une app lente = des utilisateurs mécontents. React Native offre plusieurs techniques pour garder ton app fluide, même avec des listes de 10 000 éléments !


1. Éviter les re-renders inutiles 🔄

' À chaque fois que l'état change, React re-rend le composant
' Problème : si le parent re-rend, TOUS les enfants re-rendent aussi !
' Solution : dire à React "ne re-rend que si les props changent"
``'

tsx
import React from "react";
import { View, Text } from "react-native";

// React.memo = le composant ne re-rend que si SES PROPS changent
interface TexteProps {
  label: string;
  valeur: string | number;
}

const TexteInfo = React.memo(function TexteInfo({ label, valeur }: TexteProps) {
  console.log(`🔄 Re-rend : ${label}`);
  return (
    <Text>
      {label} : {valeur}
    </Text>
  );
});

// Parent
function Dashboard({ utilisateur, stats }: { utilisateur: any; stats: any }) {
  return (
    <View>
      {/*
        TexteInfo ne re-rendra PAS si utilisateur.nom
        et stats.total n'ont pas changé
      */}
      <TexteInfo label="Nom" valeur={utilisateur.nom} />
      <TexteInfo label="Total" valeur={stats.total} />
    </View>
  );
}
``'

---

## 2. useMemo et useCallback — mémoïsation 🧠

```text
' useMemo = éviter de RECALCULER une valeur à chaque rendu
' useCallback = éviter de RECRÉER une fonction à chaque rendu

' Sans useMemo :
'   const trie = items.sort(...)  → recalculé à CHAQUE rendu !
'
' Avec useMemo :
'   const trie = useMemo(() => items.sort(...), [items])
'   → recalculé SEULEMENT si items change
import { useMemo, useCallback } from "react";

function ListeArticles({ articles }: { articles: Article[] }) {
  // useMemo : ne trier que si la liste change
  const articlesTries = useMemo(() => {
    console.log("🔄 Tri en cours...");
    return [...articles].sort((a, b) => b.note - a.note);
  }, [articles]);

  // useCallback : garder la même fonction
  const handlePress = useCallback((id: number) => {
    console.log("Article cliqué :", id);
  }, []);  // [] = jamais recréée

  return (
    <FlatList
      data={articlesTries}
      renderItem={({ item }) => (
        <ArticleCard article={item} onPress={handlePress} />
      )}
    />
  );
}
``'

---

## 3. Optimisation des images 🖼️

```text
' Les images sont la première cause de lenteur !
' Solutions :
' 1. Redimensionner les images AVANT de les charger
' 2. Utiliser des formats modernes (WebP)
' 3. Mettre en cache les images téléchargées
import { Image } from "expo-image";  // ✅ Meilleur que Image classique

// Image = chargement optimisé + cache + placeholder
<Image
  source={{ uri: "https://..." }}
  style={{ width: 200, height: 200 }}
  placeholder={{ blurhash: "L6PZfSi_.AyE_3t7t7R**0o#DgR4" }}  // Placeholder
  contentFit="cover"
  transition={300}  // Animation de fade
/>

// Redimensionnement côté serveur (ex: avec Cloudinary)
// https://res.cloudinary.com/.../w_200,h_200/image.jpg
// → L'image est déjà redimensionnée AVANT d'être téléchargée !
``'

---

## 4. Comprendre le bridge JS et JSI/Fabric 🔧

text
' Ancienne architecture (jusqu'à RN 0.67) :
' Le Bridge JSON = un tube qui ralentit tout
' Chaque communication JS <-> Native doit être "sérialisée" en JSON
' → Lent, surtout pour les animations

' Nouvelle architecture (RN 0.68+) :
' JSI (JavaScript Interface) = communication DIRECTE
' Plus besoin de sérialiser en JSON
' → 2x plus rapide !
' Fabric (nouveau renderer) + TurboModules
' → Animations à 60 FPS au lieu de 30 !
``'

---

## 5. Profiling — trouver les lenteurs 🔍

```bash
# Activer le profiling React Native
# 1. Ouvrir le menu développeur (Cmd/Ctrl + D)
# 2. "Show Perf Monitor" → FPS en temps réel
# 3. "Profile Hermes" → profiling détaillé

# React DevTools
npx react-devtools
``'

```tsx
import { Profiler } from "react";

function onRenderCallback(
  id: string,
  phase: "mount" | "update",
  actualDuration: number,
) {
  console.log(`${id} (${phase}) : ${actualDuration.toFixed(2)}ms`);
  // Si > 16ms → l'app va ralentir (60 FPS = 16ms par frame)
}

function App() {
  return (
    <Profiler id="Liste" onRender={onRenderCallback}>
      <MaListe items={items} />
    </Profiler>
  );
}
``'

---

## 6. Checklist performance ✅

| Problème | Symptôme | Solution |
|----------|----------|----------|
| **Listes lentes** | Défilement saccadé | FlatList + getItemLayout |
| **Images lourdes** | Chargement lent | Redimensionner + cache |
| **Re-renders** | Lag aux interactions | React.memo + useMemo |
| **Animations** | Saccades | Reanimated + useNativeDriver |
| **Bridge** | Tout est lent | Nouvelle archi (JSI/Fabric) |

---

## Exercices pour toi 🎯

1. **React.memo** : crée une liste de 1000 éléments avec et sans React.memo, mesure la différence de FPS
2. **FlatList optimisation** : ajoute `getItemLayout`, `windowSize` et `maxToRenderPerBatch` à ta FlatList et observe
3. **Image** : crée une galerie avec des images 2000×2000 vs images redimensionnées 200×200 — compare le temps de chargement

Création des variables pas à pas

Prêt à explorer la mémoire

Appuie sur Play pour voir les variables se créer une par une

0/4

Visualisation d'exécution

ligne 17
code
1import React, { useState, useCallback } from 'react';
2import { View, Text, TouchableOpacity, FlatList } from 'react-native';
3
4// Composant optimisé avec memo
5const Article = React.memo(({ titre, prix }: { titre: string; prix: number }) => (
6 <View>
7 <Text>{titre} - {prix}€</Text>
8 </View>
9));
10
11export default function Liste() {
12 const [compte, setCompte] = useState(0);
13 const articles = [
14 { id: '1', titre: 'Livre', prix: 15 },
15 { id: '2', titre: 'Stylo', prix: 3 },
16 ];
17
18 return (
19 <View>
20 <TouchableOpacity onPress={() => setCompte(c => c + 1)}>
21 <Text>Clics: {compte}</Text>
22 </TouchableOpacity>
23 <FlatList
24 data={articles}
25 renderItem={({ item }) => <Article titre={item.titre} prix={item.prix} />}
26 />
27 </View>
28 );
29}
Variables
Article (memo)=ne re-rend pas si props identiques
FlatList=virt. rend 2/10 000 items

⚡ React.memo — Avant / Après

❌ SANS React.memo
Enfant 0 renders
Re-rend à CHAQUE clic parent
✅ AVEC React.memo
Enfant 0 renders
Ne re-rend QUE si ses props changent