Blog d'Obi Madu
Retour à tous les articles
MobileSystem DesignInfrastructure

React Native et Expo : Le modèle mental qui fait le déclic

Comprenez comment React Native et Expo fonctionnent réellement, des builds natifs aux mises à jour OTA et aux flux de développement.

React Native et Expo : Le modèle mental qui fait le déclic

React Native est incroyablement facile à mal comprendre si vous venez principalement du développement web. Vous écrivez des composants React standard, vous utilisez JavaScript ou TypeScript, vous exécutez un serveur de développement qui vous semble familier, et vous obtenez des capacités de rafraîchissement incroyablement rapides. Parce que le flux de travail semble si proche de la création de React sur le web, il est extrêmement tentant de considérer React Native comme une simple application web soigneusement enveloppée dans une coquille mobile.

Ce modèle mental est entièrement faux.

React Native génère de véritables applications mobiles natives. L'interface utilisateur n'est fondamentalement pas rendue dans un DOM de navigateur. Il n'y a pas d'éléments div ou span, et il n'y a certainement pas de page web cachée prétendant être une application. Au lieu de cela, votre code React décrit simplement une interface native, et React Native agit comme le moteur qui transforme cette description en de véritables composants iOS et Android. Expo vient ensuite s'ajouter à React Native en aplanissant les difficultés historiques du développement mobile, fournissant une configuration native, des builds de développement, un routage basé sur les fichiers, des mises à jour OTA, des builds dans le cloud et un accès simplifié aux API courantes des appareils. Une fois que vous comprenez profondément la frontière entre l'environnement d'exécution natif et le bundle JavaScript, tout l'écosystème devient considérablement moins confus.

React Native n'est pas React DOM

React pour le web effectue le rendu directement dans le DOM du navigateur, tandis que React Native effectue le rendu vers des primitives d'interface utilisateur natives fournies par le système d'exploitation.

React webReact Native
divView
span ou pText
imgImage
DOM du navigateurVues natives iOS et Android

Lorsque vous écrivez quelque chose comme ceci :

<View style={{ backgroundColor: "red" }}>
  <Text>Hello</Text>
</View>

React Native ne génère pas de HTML sous le capot. Sur iOS, il crée des vues UIKit natives, et sur Android, il crée des vues Android natives. Cette distinction structurelle a une importance immense pour les performances, le style, l'accessibilité, les gestos, les modules natifs et le déploiement. Vous ne livrez pas un site web ; vous livrez une application native compilée dont le comportement se trouve être piloté par un moteur JavaScript.

Les deux programmes à l'intérieur de chaque application React Native

Le concept le plus critique à saisir dans React Native est que votre application est en réalité constituée de deux programmes distincts fonctionnant ensemble de manière transparente.

Votre application mobile

Environnement d'exécution natif <-> Bundle JavaScript

L'environnement d'exécution natif est l'application compilée elle-même. Il est écrit dans les langages natifs de la plateforme et strictement construit avec des outils natifs. Sur iOS, cela implique Xcode, Swift et Objective-C. Sur Android, cela signifie s'appuyer sur Gradle, Kotlin et Java. À l'inverse, le bundle JavaScript est le code réel de votre application React, qui contient vos écrans, composants, la hiérarchie de navigation, la gestion de l'état et toute la logique métier globale.

L'environnement d'exécution natif héberge le moteur JavaScript, des modules natifs personnalisés, les permissions, les métadonnées de l'application, les icônes de l'application, les écrans de démarrage et le pont vital qui permet à JavaScript de converser avec les API natives. Il est compilé, signé, spécifique à la plateforme et, ce qui est crucial, il ne peut pas être modifié sur l'appareil d'un utilisateur sans une mise à jour native formelle via l'App Store. Le bundle JavaScript est beaucoup plus flexible. Pendant le développement, il peut être chargé directement depuis votre ordinateur via un réseau local. En production, il est généralement empaqueté de manière sécurisée dans le binaire de l'application, mais avec les mises à jour OTA, il peut souvent être mis à jour à la volée sans nécessiter un examen complet de la part de l'App Store.

L'analogie du navigateur est souvent utile ici : l'environnement d'exécution natif est comme le navigateur Chrome, tandis que le bundle JavaScript est comme le site web. Vous pouvez pousser des mises à jour sur un site web à l'infini sans obliger l'utilisateur à mettre à jour Chrome, mais si vous avez besoin d'une toute nouvelle fonctionnalité de navigateur dont Chrome manque, le navigateur lui-même doit inévitablement être mis à jour.

Ce qui nécessite réellement un build natif

Cette division fondamentale explique l'une des sources de friction et de confusion les plus courantes pour les nouveaux venus : pourquoi certains changements sont mis à jour instantanément à l'écran tandis que d'autres exigent de manière frustrante un nouveau build natif complet.

ChangementBuild natif nécessaire ?Mise à jour OTA possible ?
Corriger du texte dans l'UINonOui
Ajouter un nouvel écranNonOui
Corriger la logique métierNonOui
Ajouter une bibliothèque uniquement JavaScriptNonOui
Ajouter une bibliothèque nativeOuiNon
Changer l'icône de l'appOuiNon
Changer les permissionsOuiNon

Si le changement affecte exclusivement le JavaScript, il peut généralement être rafraîchi instantanément et est généralement éligible pour une mise à jour OTA. Cependant, si le changement affecte les capacités natives de l'appareil, les permissions du système, les métadonnées binaires, ou s'il introduit de nouveaux modules natifs, vous avez absolument besoin d'un nouveau build natif. Maîtriser cette seule règle explique presque chaque décision de flux de travail de développement dans l'écosystème React Native.

Ce qu'Expo apporte

Expo est une plateforme complète construite à dessein au-dessus de React Native. Elle fournit un environnement de développement beaucoup plus complet dès le départ et masque de manière experte la grande majorité de la complexité des builds natifs jusqu'à ce que vous ayez réellement besoin d'interagir avec elle.

Dans un projet géré par Expo, vous ne voyez presque jamais les dossiers traditionnels ios/ et android/. Au lieu de cela, vous configurez élégamment le comportement natif via app.json, app.config.js, des plugins de configuration intelligents et divers paquets installés. Lorsqu'il est finalement temps de compiler l'application, Expo peut générer proprement les projets natifs nécessaires pour vous via une seule commande :

npx expo prebuild

Cette commande puissante crée les projets natifs ios/ et android/ en se basant entièrement sur votre configuration de haut niveau et les dépendances listées. Expo fournit également des modules natifs largement testés, d'excellents outils de développement, un routage basé sur les fichiers grâce à Expo Router, EAS Build pour des builds cloud gérés, EAS Submit pour la soumission automatisée à l'App Store, et EAS Update pour déployer des mises à jour JavaScript OTA. Le point fondamental n'est pas qu'Expo efface le code natif de l'existence : il se contente de gérer sa complexité à votre place.

Expo Go vs Builds de développement

Expo Go est une application précompilée très pratique, maintenue activement par l'équipe d'Expo. Vous l'installez directement depuis l'App Store, exécutez npx expo start sur votre machine, scannez un code QR avec votre téléphone, et Expo Go charge instantanément votre bundle JavaScript. C'est phénoménal pour apprendre React Native et prototipar rapidement des idées, car vous n'avez besoin de rien compiler en natif avant de voir votre application fonctionner sur un appareil physique.

La principale limitation est qu'Expo Go ne contient que les modules natifs spécifiques déjà inclus par l'équipe d'Expo. Vous ne pouvez fondamentalement pas tester chaque dépendance native possible, le comportement personnalisé des icônes de l'application, les mécaniques d'écran de démarrage en production, les liens universels ou les configurations complexes de notifications push à distance de manière native à l'intérieur.

Un build de développement est totalement différent. C'est le propre binaire de votre application, explicitement compilé pour le développement, avec la bibliothèque expo-dev-client installée. Vous pouvez facilement le considérer comme votre propre version personnalisée d'Expo Go. Il inclut réellement les modules natifs spécifiques dont votre application a légitimement besoin pour fonctionner en production.

FonctionnalitéExpo GoBuild de développement
InstallationInstaller depuis l'App StoreCompiler votre propre app
Bibliothèques nativesLimitées aux modules inclus d'Expo GoN'importe quelle bibliothèque native
Icône et écran de démarragePas votre app finaleVotre vraie configuration
Notifications pushLimitéesTests réalistes
Meilleure utilisationApprentissage et prototypesDéveloppement d'app sérieux

La règle pratique est remarquablement simple : commencez avec Expo Go s'il offre suffisamment de fonctionnalités pour vos besoins actuels, mais passez aux builds de développement dès l'instant où votre application exige un comportement natif ou des bibliothèques tierces qu'Expo Go ne peut tout simplement pas fournir.

Le développement et la production chargent le JavaScript différemment

Dans un environnement de développement, votre téléphone physique charge généralement le bundle JavaScript en continu depuis Metro, qui est le serveur de développement local fonctionnant de manière transparente sur votre ordinateur.

Téléphone exécutant Expo Go ou un build de développement
        |
        | demande le bundle JavaScript
        v
Serveur de développement Metro sur votre ordinateur

Ce mécanisme est exactement la raison pour laquelle votre téléphone et votre ordinateur doivent typiquement être connectés exactement au même réseau Wi-Fi. C'est aussi la raison sous-jacente pour laquelle Fast Refresh fonctionne si bien : l'application interroge en permanence le code depuis un serveur de développement actif.

En production, l'architecture change fondamentalement. Le bundle JavaScript finalisé est empaqueté de manière sécurisée à l'intérieur du binaire de l'application lui-même.

VotreApp.apk ou VotreApp.ipa
  code natif
  assets
  main.jsbundle

L'application de production n'a évidemment pas besoin de se connecter à votre ordinateur local. Elle peut se lancer parfaitement hors ligne, et le JavaScript est fortement optimisé et explicitement groupé pour les performances. EAS Update introduit un modèle hybride très attrayant. L'application est initialement livrée avec une version JavaScript intégrée en toute sécurité, mais au lancement, elle peut vérifier discrètement s'il y a de nouvelles mises à jour JavaScript et les mettre en cache dynamiquement sur l'appareil. Cette capacité est incroyablement puissante pour livrer des corrections de bugs et des mises à jour d'interface de manière transparente, mais elle comporte une limite dure et inflexible : les mises à jour OTA ne peuvent absolument pas ajouter de nouvelles capacités ou modules natifs.

La structure d'un projet Expo

Un projet géré par Expo est typiquement structuré pour séparer proprement le code JavaScript pur, la configuration native globale, les actifs statiques et la configuration de build essentielle.

votre-projet/
  app/              écrans et routes
  components/       UI réutilisable
  hooks/            hooks personnalisés
  constants/        valeurs partagées
  assets/           images et polices
  app.json          configuration native de l'app
  package.json      dépendances
  eas.json          config. de build et de mise à jour EAS

Le fichier app.json contrôle de manière exhaustive les métadonnées cruciales de l'application native.

{
  "expo": {
    "name": "My App",
    "slug": "my-app",
    "icon": "./assets/icon.png",
    "android": {
      "package": "com.company.myapp"
    },
    "ios": {
      "bundleIdentifier": "com.company.myapp"
    }
  }
}

Le fichier package.json a une importance critique car les dépendances qui y sont listées peuvent fréquemment inclure des modules natifs. Installer un paquet purement JavaScript et installer un paquet contenant du code natif sont des actions fondamentalement différentes avec des implications très différentes pour votre pipeline de build.

React Native est toujours du code Frontend

Bien que React Native puisse donner à une application mobile une sensation incroyablement native, il ne transforme absolument pas par magie le code frontend en code backend. Une application React Native ne devrait absolument jamais se connecter directement à une base de données de production. Elle ne doit pas contenir d'identifiants de base de données bruts, et elle ne doit jamais stocker de secrets d'API privés dans son bundle. Les fichiers APK et IPA peuvent être trivialement inspectés par n'importe qui, et les bundles JavaScript peuvent facilement être extraits par des acteurs malveillants.

L'architecture correcte et sécurisée reste exactement la même que pour la plupart des systèmes frontend modernes :

Application mobile <-> API Backend <-> Base de données

L'application mobile doit communiquer strictement avec votre API via un HTTPS sécurisé. Votre API gère ensuite en toute sécurité l'authentification complexe, l'autorisation robuste, la validation approfondie, la limitation de débit stricte et l'accès privé à la base de données. La base de données reste entièrement privée et cachée du client mobile. Exposer une URL d'API dans le code client est parfaitement normal, car les utilisateurs peuvent déjà facilement intercepter et voir le trafic réseau depuis leurs propres appareils. La sécurité véritable ne vient pas de la dissimulation de l'URL de l'API ; elle vient entièrement d'une authentification appropriée, d'une autorisation et d'une application stricte des règles côté serveur.

Les outils de Backend-as-a-service tels que Supabase et Firebase continuent de respecter strictement ce modèle. Le client communique de manière sécurisée avec une couche d'API intermédiaire, n'utilisant jamais directement d'identifiants de base de données bruts avec un accès illimité. Par exemple, la clé publique "anon" de Supabase est explicitement conçue pour être exposée en toute sécurité au client, mais elle doit inévitablement être associée à une authentification appropriée et à une sécurité stricte au niveau des lignes côté base de données.

const supabase = createClient(
  "https://xyz.supabase.co",
  "public-anon-key"
);

const { data } = await supabase
  .from("interviews")
  .select("*");

La sécurité sous-jacente provient intrinsèquement des règles strictes qui s'exécutent activement derrière l'API, et non pas du fait de prétendre que la clé côté client est un secret jalousement gardé.

Le modèle mental à conserver

En fin de compte, React Native est simplement un conteneur natif exécutant une application JavaScript très performante. Expo agit comme la plateforme robuste qui rend ce conteneur beaucoup plus facile à configurer, à compiler, à mettre à jour de manière transparente et finalement à livrer aux utilisateurs. Expo Go est un conteneur précompilé partagé extrêmement utile, tandis qu'un build de développement agit comme votre propre conteneur entièrement personnalisé. Une mise à jour OTA modifie uniquement le JavaScript s'exécutant à l'intérieur de ce conteneur, de manière totalement distincte du conteneur lui-même.

Une fois que vous voyez et respectez clairement cette limite, l'ensemble de l'écosystème prend beaucoup plus de sens. Vous comprenez instinctivement pourquoi l'ajout d'un nouvel écran est instantané, pourquoi l'ajout d'une bibliothèque native exige un nouveau build, pourquoi Expo Go finit par ne plus suffire pour les applications complexes, et pourquoi les applications mobiles nécessitent invariablement un backend sécurisé et dédié. C'est toute la courbe d'apprentissage de React Native et d'Expo condensée en un seul concept global : comprenez ce qui vit en toute sécurité dans JavaScript, ce qui vit strictement dans le code natif, et exactement ce qui traverse la frontière critique entre les deux.

Références