MFormations
Modern Mobile Engineering

Chapitre 8

08 - React Native

08 - React Native

08 - React Native : Cours complet

Table des matières

  1. Architecture RN : moteurs JS, bridge
  2. La nouvelle architecture (TurboModules, Fabric, Hermes)
  3. Expo : managed workflow, EAS, dev clients
  4. React Navigation
  5. Styling : StyleSheet, NativeWind, styled-components
  6. Reanimated et gestures
  7. State management : Zustand, Redux Toolkit, React Query
  8. OTA updates : CodePush, Expo Updates
  9. Performance
  10. Résumé et checklist

1. Architecture RN : moteurs JS, bridge

1.1 Le principe

React Native exécute du JavaScript dans un moteur séparé et rend des composants natifs (UIView / ViewGroup). L'application a :

  • le thread JS (logique, state) ;
  • le thread UI natif (rendu, gestes) ;
  • depuis l'architecture originale, un bridge sérialisé.

1.2 JavaScriptCore vs Hermes

MoteurRôle
JavaScriptCoreMoteur historique (Safari). Premier choix, moins performant pour RN
HermesMoteur optimisé par Meta pour RN : démarrage plus rapide, moins de mémoire, bytecode précompilé

Hermes est le défaut sur Android depuis RN 0.70 et sur iOS depuis RN 0.70+ (configurable).

1.3 Le bridge (ancienne architecture)

Diagramme en cours de génération...

Le bridge :

  • sérialise les messages en JSON (coût) ;
  • est asynchrone et non batching natif ;
  • complique les types (objets passés par copie).

1.4 Les problèmes du bridge

  • Appels lents (JSON ser/de).
  • Impossibilité de passer des objets complexes.
  • Fragmentation : chaque module a sa propre implémentation.

→ La nouvelle architecture les résout.


2. La nouvelle architecture

2.1 Les piliers

  1. TurboModules : modules natifs chargés paresseusement, avec des JSI bindings (pas de JSON).
  2. Fabric : système de rendu (C++), avec l'arbre de vues partagé entre JS et natif.
  3. JSI (JavaScript Interface) : couche C++ permettant de partager des objets natifs avec JS (types, performance).
  4. Codegen : génération de code C++/Java/ObjC depuis les specs TypeScript.
  5. Interop Layer : compatibilité avec les anciens modules (bridge).

2.2 Schéma nouvelle architecture

Diagramme en cours de génération...

2.3 États

  • RN 0.74+ : nouvelle architecture activée par défaut (Android + iOS).
  • La plupart des libs compatibles.
  • RN 0.80 (2025) : le bridge legacy est supprimé/optionnel.

2.4 Pourquoi c'est mieux

  • Temps de démarrage réduit (JSI, Hermes bytecode).
  • Meilleure interaction JS↔natif (types, synchronie partielle).
  • Meilleure performance de rendu (Fabric priorise la mise à jour).
  • Support de useSyncExternalStore et des concurrent features de React.

3. Expo : managed workflow, EAS, dev clients

3.1 Qu'est-ce qu'Expo ?

Framework + écosystème au-dessus de React Native : outils, config, SDK, services cloud.

3.2 Workflows

WorkflowDescription
Managed (Expo Go)Zéro config native, développement rapide, config via app.json
Development buildBuild personnalisé avec modules natifs custom, via dev clients
Bare/PrebuildContrôle total des dossiers android/ et ios/ (générés par expo prebuild)

3.3 Commencer

npx create-expo-app@latest mon-app
cd mon-app
npx expo start          # QR code, Expo Go ou dev client

3.4 EAS (Expo Application Services)

  • Build : builds cloud (Android AAB/APK, iOS IPA) sans machine macOS.
  • Submit : soumission aux stores.
  • Update : mises à jour OTA.
npm install -g eas-cli
eas build --platform android
eas submit
eas update --channel production

3.5 Dev clients

npx expo run:android     # build local natif
npx expo-dev-client

Le dev client combine hot reload + accès aux modules natifs personnalisés.

3.6 Config plugins

Modifie la config native (Info.plist, AndroidManifest) via app.json :

{
  "expo": {
    "plugins": [
      ["expo-camera", { "cameraPermission": "Autoriser la caméra ?" }]
    ]
  }
}

4. React Navigation

4.1 Fondations

React Navigation est la solution standard de navigation RN.

import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: true }}>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Detail" component={DetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

4.2 Types

export type RootStackParamList = {
  Home: undefined;
  Detail: { productId: number };
};

Typage du navigation prop :

type Props = NativeStackScreenProps<RootStackParamList, "Detail">;

4.3 Les navigateurs

  • createNativeStackNavigator : natif (meilleures perfs, gestures iOS).
  • createBottomTabNavigator : tab bars.
  • createDrawerNavigator : drawer.
  • @react-navigation/material-top-tabs : tabs haut.

4.4 Patterns

  • Paramètres : navigation.navigate("Detail", { productId: 42 }).
  • Back : navigation.goBack().
  • Deep links via config :
const linking = {
  prefixes: ["myapp://", "https://example.com"],
  config: { screens: { Home: "", Detail: "product/:productId" } },
};

5. Styling : StyleSheet, NativeWind, styled-components

5.1 StyleSheet

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

const styles = StyleSheet.create({
  card: {
    backgroundColor: "#fff",
    borderRadius: 12,
    padding: 16,
    gap: 8,
  },
  title: { fontSize: 16, fontWeight: "600" },
});

<View style={styles.card}>
  <Text style={styles.title}>Bonjour</Text>
</View>;
  • Flexbox par défaut, unités en points (pas de px).
  • gap supporté.

5.2 NativeWind

Tailwind CSS pour RN (v4+ : className natif).

<View className="bg-white rounded-2xl p-4 gap-2">
  <Text className="text-base font-semibold text-slate-900">Bonjour</Text>
</View>

5.3 styled-components

import styled from "styled-components/native";

const Card = styled.View`
  background: white;
  border-radius: 12px;
  padding: 16px;
`;

const Title = styled.Text`
  font-size: 16px;
  font-weight: 600;
`;

5.4 Choix

SolutionApprochePour qui
StyleSheetNative, statiqueLe plus simple
NativeWindUtility-firstÉquipes Tailwind
styled-componentsCSS-in-JS dynamiqueThèmes dynamiques

6. Reanimated et gestures

6.1 Reanimated

Animations exécutées sur le thread UI natif (worklets), 60/120 fps.

import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";

function LikeButton() {
  const scale = useSharedValue(1);

  const style = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  return (
    <Animated.View style={style}>
      <Pressable
        onPress={() => (scale.value = withSpring(scale.value === 1 ? 1.3 : 1))}
      >
        <Text>❤️</Text>
      </Pressable>
    </Animated.View>
  );
}

6.2 Worklets

Les fonctions marquées 'worklet' s'exécutent sur le thread UI.

const handleGesture = useAnimatedGestureHandler({
  onStart: () => { "worklet"; },
  onActive: (event) => { translation.value = event.translationX; },
});

6.3 React Native Gesture Handler

Gestes natifs (pan, tap, pinch, rotation, fling).

import { Gesture, GestureDetector } from "react-native-gesture-handler";

const pan = Gesture.Pan()
  .onUpdate((e) => { translation.value = e.translationX; })
  .onEnd(() => { translation.value = withSpring(0); });

<GestureDetector gesture={pan}>
  <Animated.View style={style} />
</GestureDetector>;

6.4 Bonnes pratiques

  • Animations UI → Reanimated (pas de Animated legacy pour les cas intenses).
  • Gestes → Gesture Handler.
  • Les transitions de navigation natifs : laisser le navigateur les gérer.

7. State management : Zustand, Redux Toolkit, React Query

7.1 Catégories d'état

  1. État serveur : données API → React Query / TanStack Query.
  2. État global client : thème, panier, session → Zustand, Redux Toolkit, Context.
  3. État local : useState/useReducer.

7.2 Zustand

Léger, simple, basé sur hooks.

import { create } from "zustand";

interface CartState {
  items: CartItem[];
  add: (item: CartItem) => void;
  remove: (id: number) => void;
}

export const useCart = create<CartState>((set) => ({
  items: [],
  add: (item) => set((s) => ({ items: [...s.items, item] })),
  remove: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id) })),
}));

// usage
const items = useCart((s) => s.items);
const add = useCart((s) => s.add);

7.3 Redux Toolkit

Standard structuré (slices, thunks, RTK Query).

import { createSlice } from "@reduxjs/toolkit";

const cartSlice = createSlice({
  name: "cart",
  initialState: { items: [] as CartItem[] },
  reducers: {
    add(state, action) { state.items.push(action.payload); },
    remove(state, action) { state.items = state.items.filter((i) => i.id !== action.payload); },
  },
});

7.4 React Query (TanStack Query)

Gère le cache serveur : fetch, retry, invalidation, refetch.

import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";

function useProducts() {
  return useQuery({
    queryKey: ["products"],
    queryFn: () => api.getProducts(),
  });
}

function useAddToCart() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (item: CartItem) => api.add(item),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["cart"] }),
  });
}

7.5 Recommandations

  • Par défaut : React Query pour le serveur + Zustand pour le global + useState pour le local.
  • Redux Toolkit : pour les grosses équipes/processus déjà en place.
  • Éviter de mettre l'état serveur dans le state global.

8. OTA updates : CodePush, Expo Updates

8.1 Pourquoi OTA ?

Distribuer une correction sans passer par la review des stores. Limité au bundle JS (pas de code natif).

Diagramme en cours de génération...

8.2 Expo Updates

{
  "expo": {
    "updates": { "url": "https://u.expo.dev/...", "enabled": true },
    "runtimeVersion": "1.0.0"
  }
}
eas update --channel production
  • runtimeVersion : change quand le code natif change → force une mise à jour store.
  • Les updates ne remplacent jamais un build natif pour les changements natifs.

8.3 CodePush (Microsoft App Center)

appcenter codepush release-react -a owner/App -d Production

8.4 Précautions OTA

  • Ne pas distribuer de changements qui exigent des permissions natives.
  • Rollout progressif (channels production/beta).
  • Monitoring : si l'update casse l'app, les users restent coincés → rollback rapide prévu.
  • Health checks et releaseVersion cohérents.

9. Performance

9.1 Mesurer

  • Metro : npx react-native start avec bundle stats.
  • React DevTools → Profiler.
  • Flipper (légacy) / modern debugging (Hermes CDP).
  • Profiler natif (Xcode Instruments, Android Studio CPU).
  • Expo : npx expo start --profiler.

9.2 Les leviers

LevierAction
MoteurHermes activé
RenduNouvelle architecture (Fabric)
ListesFlatList avec getItemLayout, initialNumToRender, windowSize
ImagesresizeMode, dimensions natives, cache (expo-image)
Re-rendersmemo, useCallback, clés stables, sélecteurs Zustand
Thread UIReanimated pour les animations
BundleMetro : import lazy, new Arch, trim des modules
Hermes bytecodePrécompilation du bundle

9.3 FlatList optimisé

<FlatList
  data={products}
  keyExtractor={(item) => String(item.id)}
  renderItem={({ item }) => <MemoProductRow product={item} />}
  initialNumToRender={10}
  windowSize={7}
  maxToRenderPerBatch={10}
  updateCellsBatchingPeriod={50}
  getItemLayout={(_, index) => ({ length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index })}
/>

9.4 Startup time

  • Réduire le travail dans index.js (lazy import des écrans).
  • Éviter les modules natifs lourds au démarrage (TurboModules paresseux).
  • Splash screen minimal puis lazy hydrate.

10. Résumé et checklist

10.1 Points clés

  • Architecture : JS thread + UI natif ; Hermes ; JSI.
  • Nouvelle architecture : TurboModules, Fabric, codegen — par défaut.
  • Expo : managed/prebuild, EAS build/submit/update, dev clients.
  • React Navigation : stack/tabs/drawer typés, deep links.
  • Styling : StyleSheet natif, NativeWind, styled-components.
  • Reanimated (worklets) + Gesture Handler : 60/120 fps.
  • State : React Query (serveur) + Zustand (global) + useState (local).
  • OTA : Expo Updates / CodePush, runtimeVersion, rollout.
  • Performance : Hermes, Fabric, FlatList, memo, Reanimated.

10.2 Checklist

  • J'explique le bridge vs TurboModules/Fabric
  • J'active Hermes et la nouvelle architecture
  • Je crée un projet Expo et un dev client
  • Je navigue avec des routes typées
  • Je stylise avec StyleSheet ou NativeWind
  • J'anime avec Reanimated et un geste
  • Je gère l'état serveur (React Query) et global (Zustand)
  • Je publie une mise à jour OTA
  • J'optimise une FlatList

Prochain chapitre

09-Flutter : Dart, widgets, state management, layout, navigation, animations, performance, tests, build.