E-NO
Applications mobiles 8 min de lecture

Concepts avancés React Native expliqués avec exemples pratiques

calendar_today Publié : 2026-07-17
update Dernière mise à jour : 2026-07-17
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Concepts avancés React Native expliqués avec exemples pratiques ».

Introduction

Ce guide explique les concepts avancés de React Native avec des exemples pratiques que vous pouvez exécuter localement. Nous nous concentrons sur la Nouvelle Architecture (Fabric, TurboModules, JSI), le threading et la performance, l'UI native, les flux de données, les paiements (Google Play Billing et Stripe), et l'intégration avec Expo. Vous apprendrez comment ces pièces s'articulent, quand elles sont pertinentes et comment les adopter sereinement en production.

Vue d'ensemble du workflow

Un workflow d'ingénierie clair et reproductible rend les sujets avancés gérables :

  1. Clarifier les objectifs
  • Plateformes : Android, iOS, Expo
  • Budgets : temps de démarrage, mémoire, FPS, taille du bundle
  • Contraintes : paiements, support hors ligne, appareils d'entrée de gamme
  1. Choisir l'architecture
  • Activer Hermes sur toutes les nouvelles apps
  • Privilégier la Nouvelle Architecture quand les dépendances la supportent
  1. Implémenter les modules
  • Déplacer les chemins natifs critiques ou bavards vers TurboModules ou JSI
  1. Construire l'UI sur Fabric au besoin
  • Créer des vues natives uniquement quand les primitives React sont insuffisantes
  1. Optimiser les flux de données
  • Concevoir les appels REST avec annulation, mise en cache et support hors ligne
  1. Ajouter les paiements
  • Isoler Google Play Billing et Stripe dans des modules natifs
  • Valider les achats côté serveur
  1. Tester localement
  • Mesurer le démarrage, les FPS, la mémoire et la récupération d'erreurs
  1. Déployer progressivement
  • Utiliser des feature flags et surveiller la diversité des appareils

Plongée dans l'architecture React Native

Pièces clés :

  • Hermes : un moteur JavaScript compact optimisé pour le mobile, améliorant le démarrage et la mémoire
  • JSI (JavaScript Interface) : une interface C++ permettant à JavaScript d'appeler du code natif sans la surcharge de sérialisation JSON
  • TurboModules : le système de modules utilisant JSI pour des appels de méthodes plus rapides et le chargement paresseux
  • Fabric : le nouveau renderer qui synchronise les mises à jour UI avec un moteur de layout concurrent (Yoga) et améliore la cohérence entre plateformes

Quand adopter :

  • Activer Hermes sur toutes les nouvelles apps
  • Utiliser TurboModules quand les appels JS-vers-natif sont fréquents ou intensifs en calcul
  • Construire des composants Fabric pour de l'UI personnalisée haute performance

Exemple minimal de fonction JSI (Android C++)

Exposer un helper natif rapide via JSI pour un chemin critique (par exemple, une simple opération sur chaîne).

// cpp/JSIStringUtil.cpp
#include <jsi/jsi.h>
#include <string>
#include <cctype>

using namespace facebook;

void installStringUtil(jsi::Runtime &rt) {
  auto toUpper = jsi::Function::createFromHostFunction(
    rt,
    jsi::PropNameID::forAscii(rt, "toUpperFast\)),
    1,
    [](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) -> jsi::Value {
      if (count < 1 || !args[0].isString()) {
        throw jsi::JSError(rt, "toUpperFast requires a string");
      }
      auto s = args[0].asString(rt).utf8(rt);
      for (auto &c : s) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
      return jsi::String::createFromUtf8(rt, s);
    }
  );
  rt.global().setProperty(rt, "toUpperFast", std::move(toUpper));
}
// android/src/main/java/com/example/MyPackage.java
public class MyPackage implements ReactNativeHost.ReactInstanceEventListener {
  @Override
  public void onReactContextInitialized(ReactContext context) {
    System.loadLibrary("jsi_stringutil");
    ReactApplicationContext rac = (ReactApplicationContext) context;
    rac.runOnNativeModulesQueueThread(() -> {
      com.example.StringUtilInstaller.install(rac);
    });
  }
}
// Utilisation JS
const out = globalThis.toUpperFast("hello");

Utilisez ce patron seulement quand un profilage réel montre que JS est le goulot d'étranglement.

Threading, rendu et performance

Threads :

  • Le thread JS exécute la logique applicative
  • Le thread UI gère les mises à jour de vue et les entrées
  • Fabric peut utiliser un thread de rendu pour monter les mises à jour
  • TurboModules peuvent utiliser des pools d'arrière-plan pour le travail natif

Lignes directrices :

  • Garder le travail sur le thread JS minimal ; découper les longues boucles avec setImmediate ou requestAnimationFrame
  • Regrouper les mises à jour d'état et éviter les re-rendus inutiles (mémoïser les enfants coûteux)
  • Déléguer le travail lourd au natif via JSI ou des tâches d'arrière-plan
  • Éviter les bridges synchrones et les gros payloads JSON

Astuces de rendu :

  • Aplatir les hiérarchies de vues
  • Utiliser FlatList avec getItemLayout approprié quand possible
  • Éviter de créer de nouveaux objets/tableaux dans les props au rendu ; mémoïser les styles
  • Privilégier Animated ou les animations natives pour les cas complexes

Helper rapide :

// Mise à jour d'état débouncée pour réduire les re-rendus
function useDebounced<T>(value: T, ms = 150) {
  const [v, setV] = React.useState(value);
  React.useEffect(() => {
    const t = setTimeout(() => setV(value), ms);
    return () => clearTimeout(t);
  }, [value, ms]);
  return v;
}

Modules natifs et composants UI

Plan TurboModule :

  1. Définir une spec TypeScript pour l'API de votre module
  2. Implémenter le code natif par plateforme
  3. Utiliser codegen pour produire des liaisons typées

Exemple de spec (infos appareil) :

// DeviceSpec.ts
export interface Spec {
  getFreeMemory(): Promise<number>;
}

Esquisse d'implémentation Android :

class DeviceModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
  override fun getName() = "DeviceModule"
  @ReactMethod
  fun getFreeMemory(promise: Promise) {
    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val mi = ActivityManager.MemoryInfo()
    am.getMemoryInfo(mi)
    promise.resolve(mi.availMem.toDouble())
  }
}

Plan vue Fabric (ProgressBar) :

  • Props : value (0..100), color
  • Le natif dessine une barre simple et émet onComplete à 100
  • Valider les props et contraindre les valeurs hors plage

Sécurité :

  • Valider les entrées dans le code natif
  • Garder les méthodes idempotentes
  • Émettre des erreurs descriptives pour les cas récupérables

Données, réseau et hors ligne

Annulation et mise en cache :

// fetchWithCache.ts
const memCache = new Map<string, any>();

export async function fetchWithCache(
  url: string,
  opts?: RequestInit & { cacheKey?: string; signal?: AbortSignal }
) {
  const key = opts?.cacheKey ?? url;
  const cached = memCache.get(key);
  if (cached) {
    // Servir le cache d'abord, puis rafraîchir en arrière-plan
    setTimeout(() => refresh(url, key).catch(() => {}), 0);
    return cached;
  }
  return refresh(url, key, opts?.signal);
}

async function refresh(url: string, key: string, signal?: AbortSignal) {
  const res = await fetch(url, { signal });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const json = await res.json();
  memCache.set(key, json);
  return json;
}

File de mutations hors ligne :

import AsyncStorage from "@react-native-async-storage/async-storage\);\
import NetInfo from "@react-native-community/netinfo\);

type Job = { id: string; url: string; body: any; method: string };\
const KEY = "offlineQueue\);\

export async function enqueue(job: Job) {\
  const raw = (await AsyncStorage.getItem(KEY)) || "[]\);
  const arr: Job[] = JSON.parse(raw);\
  arr.push(job);\
  await AsyncStorage.setItem(KEY, JSON.stringify(arr));\
}\
\
export async function flush() {\
  const state = await NetInfo.fetch();\
  if (!state.isConnected) return;\
  const raw = (await AsyncStorage.getItem(KEY)) || "[]\);
  const arr: Job[] = JSON.parse(raw);\
  const next: Job[] = [];\
  for (const j of arr) {\
    try {\
      const res = await fetch(j.url, {\
        method: j.method,\
        body: JSON.stringify(j.body),\
        headers: { "Content-Type": "application/json" }\
      });\
      if (!res.ok) throw new Error(String(res.status));\
    } catch (e) {\
      next.push(j); // garder pour retry\
    }\
  }\
  await AsyncStorage.setItem(KEY, JSON.stringify(next));\
}\

Conseils serveur :

  • Endpoints idempotents pour tolérer les retentatives
  • Tokens à durée de vie courte ; rotation régulière

Exemples de paiements

Flux Google Play Billing (Android) :

  • Initialiser BillingClient une fois au démarrage de l'app
  • Interroger les détails produits avec queryProductDetailsAsync
  • Lancer le flux d'achat sur le thread UI via launchBillingFlow
  • Recevoir le token d'achat dans onPurchasesUpdated ; acquitter ou consommer
  • Valider le token d'achat sur votre serveur avant d'accorder l'entitlement

Flux Stripe :

  • Utiliser les SDK natifs pour présenter PaymentSheet (iOS) ou PaymentSheet via le SDK Stripe Android
  • Ne jamais manipuler de données de carte brutes en JS
  • Créer un PaymentIntent côté serveur ; confirmer avec le client secret dans l'app

API de module partagé (esquisse) :

// Payments.ts
export interface PaymentsSpec {
  isReady(): Promise<boolean>;
  listProducts(skus: string[]): Promise<{ sku: string; price: string }[]>;
  startPurchase(sku: string): Promise<{ success: boolean; token?: string; error?: string }>;
  presentPaymentSheet(clientSecret: string): Promise<{ success: boolean; error?: string }>;
}

Gestion d'erreurs :

  • Distinguer les annulations utilisateur des échecs
  • Réessayer les erreurs réseau transitoires avec backoff exponentiel
  • Logger les états d'achat pour audit et réconciliation

Expo et la Nouvelle Architecture

  • Hermes est activé par défaut dans les SDK Expo modernes (SDK 48+)
  • Utiliser expo prebuild quand vous avez besoin de modules natifs personnalisés (billing, Stripe)
  • Maintenir les versions natives alignées avec votre runtime version Expo
  • Pour les paiements, prévoir prebuild ou config plugins pour inclure les SDK natifs

Plan de pilote local

Objectif : valider Hermes, un TurboModule, une vue Fabric, l'annulation REST et une interface paiements sûre.

Étapes :

  1. Activer Hermes et mesurer le cold start sur un Android milieu de gamme (ex. Snapdragon 765G)
  2. Ajouter un TurboModule exposant getFreeMemory() et l'afficher dans un écran
  3. Implémenter une ProgressBar Fabric avec props value et color ; marquer complet à 100
  4. Construire un wrapper fetchWithCache avec AbortController ; annuler les requêtes à la navigation
  5. Créer une interface PaymentsModule et utiliser des réponses mock en debug ; cacher la vraie UI derrière un feature flag
  6. Ajouter des error boundaries et boutons de retry pour les appels réseau
  7. Définir les métriques de succès : démarrage < 2s, 60 fps fluides sur scroll liste, requête annulée ne met jamais à jour l'état après unmount, flux paiements mock fonctionne bout en bout
  8. Rédiger un script de test manuel court et l'exécuter sur simulateurs Android/iOS et au moins un appareil Android physique

Critères de sortie :

  • Toutes les métriques atteintes
  • Aucune promesse rejetée non gérée
  • Logs montrant init et teardown propres sans fuites

Conclusion

Vous avez vu comment Hermes, JSI (JavaScript Interface), TurboModules et Fabric s'emboîtent, comment raisonner sur les threads et le rendu, et comment structurer données et paiements sereinement. Commencez par le pilote, mesurez les gains réels, puis étendez module par module. Gardez les changements derrière des flags, validez sur appareils de toutes gammes, et documentez les contrats entre JS et natif pour que les équipes évoluent en confiance.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO