Une plongée à froid dans React Native (tutoriel pour débutants)
Publié: 2022-03-11Lorsque React Native a été annoncé, les premières réactions ont été extrêmement positives. Traditionnellement, lorsque nous pensons aux technologies Web dans l'espace mobile, des choses comme Apache Cordova nous viennent à l'esprit, qui nous permettent de regrouper des sites Web ou des applications Web en tant qu'applications pour plates-formes mobiles. Dans ce didacticiel pour débutants, nous examinerons l'architecture de React Native, la philosophie derrière React Native et en quoi elle diffère des autres solutions dans le même espace. A la fin de l'article, nous aurons transformé une application React « Hello World » en une application React Native.
Commençons par dire que React Native est une technologie relativement nouvelle. Il est officiellement disponible depuis mars 2015, après avoir été en version bêta privée depuis le début de cette année, et utilisé en interne sur Facebook pendant un certain temps auparavant. Le dicton « Rome ne s'est pas construite en un jour » s'applique généralement aussi à la technologie. Des outils comme grunt
et des plateformes comme Node.js ont mis des années à mûrir. Dans le monde du Web, les choses évoluent rapidement, et avec un grand nombre de frameworks, de packages et d'outils qui sortent chaque jour, les développeurs ont tendance à devenir un peu plus sceptiques et ne veulent pas sauter dans tous les trains à la mode pour se rendre compte que ils se sont retrouvés dans une situation de verrouillage du fournisseur. Nous verrons ce qui rend React Native spécial, pourquoi c'est une technologie qui vaut la peine d'être abordée, et couvrirons quelques cas où ce ne sont pas tous des licornes et des arcs-en-ciel.
Sous la capuche
Lorsqu'on parle de technologies Web sur mobile, les solutions disponibles entrent généralement dans l'une des catégories suivantes.
Regroupement d'applications Web dans un navigateur Web mobile
L'application Web réside dans un navigateur mobile, généralement appelé WebView. Sans aucune refactorisation majeure, un site Web ou une application Web fonctionne sur l'appareil mobile. Nous devrons peut-être prendre en compte les événements du navigateur mobile tels que le tapotement ou l'écoute des changements d'orientation de l'appareil et le plus petit écran pour une expérience utilisateur complète, mais nous avons une version mobile fonctionnelle avec un minimum d'effort. Cordova/PhoneGap est l'option la plus populaire dans cette catégorie. Malheureusement, cette option présente un gros inconvénient : dans certains cas, les applications développées à l'aide de Cordova sont nettement plus lentes que les applications natives, en particulier pour les applications à forte charge graphique. Dans d'autres cas, le système d'exploitation mobile ne fournit pas toutes les fonctionnalités de WebView disponibles dans le navigateur mobile. L'expérience utilisateur peut également différer des applications natives ; cela peut se produire en raison de l'application ou de la plate-forme elle-même. Ce problème peut aller de barres de défilement ne se sentant pas de la même manière à un retard notable lorsque vous appuyez sur des éléments.
Compilation vers les technologies natives
Une solution complètement différente consiste à créer une base de code native à la fin. Cela se produit en transformant le code source d'origine dans un autre langage de programmation. Nous échangeons les performances natives contre une couche d'abstraction avec quelques incertitudes. Dans le cas des solutions fermées, nous ne savons même pas ce qui se passe sous le capot et à quel type de boîte noire nous avons affaire. Dans d'autres cas, nous ne savons pas dans quelle mesure la prochaine mise à jour du système d'exploitation mobile cassera notre code et quand des correctifs ou des mises à jour seront disponibles. Un exemple populaire de cette catégorie serait Haxe.
Utiliser une couche JavaScript
Ici, nous utilisons le moteur JavaScript de l'environnement mobile et y exécutons notre JavaScript. Les contrôles natifs sont mappés sur des objets et des fonctions JavaScript. Ainsi, lorsque nous devions appeler une fonction appelée fancyButtonRightHere()
, un bouton apparaissait à l'écran. NativeScript ou Appcelerator Titanium sont des exemples bien connus de cette catégorie.
React Native pourrait être classé dans la troisième catégorie. Pour les versions iOS et Android, React Native utilise JavaScriptCore sous le capot, qui est le moteur JavaScript par défaut sur iOS. JavaScriptCore est également le moteur JavaScript des navigateurs Safari d'Apple. Les développeurs OS X et iOS peuvent en fait s'interfacer directement avec lui s'ils le souhaitent.
Une grande différence est que React Native exécute le code JavaScript dans un thread séparé, de sorte que l'interface utilisateur ne se bloque pas et que les animations doivent être soyeuses et fluides.
React est la fonctionnalité clé
Il convient de noter que le "React" dans React Native n'est pas mis là par accident. Pour React Native, nous avons besoin de comprendre exactement ce que propose React. Les concepts suivants fonctionnent de la même manière dans React et React Native, bien que ces exemples de code soient conçus pour être exécutés dans le navigateur.
Point d'entrée de rendu unique
Lorsque nous examinons un composant React simple, la première chose que nous pouvons remarquer est que le composant a une fonction de render
. En fait, React génère une erreur s'il n'y a pas de fonction de rendu définie dans le composant.
var MyComponent = function() { this.render = function() { // Render something here }; };
La particularité est que nous ne manipulons pas les éléments DOM ici, mais nous renvoyons une construction basée sur XML qui représente ce qui sera rendu dans le DOM. Cette construction basée sur XML est appelée JSX.
var MyComponent = function() { this.render = function() { return <div className="my-component">Hello there</div>; }; };
Un transformateur JSX spécial prend tout ce code d'apparence XML et le convertit en fonctions. Voici à quoi ressemblera le composant après la transformation :
var MyComponent = function() { this.render = function() { return React.createElement("div", { className: "my-component" }, "Hello there"); }; };
Le plus grand avantage est qu'en jetant un coup d'œil rapide au composant, nous savons toujours ce qu'il est censé faire. Par exemple, un <FriendList />
peut restituer un certain nombre de composants <Friend />
. Nous ne pouvons rendre nos composants nulle part ailleurs que dans la fonction de render
, il n'y a donc jamais de souci que nous ne sachions pas exactement d'où vient notre composant rendu.
Flux de données unidirectionnel
Pour construire le contenu d'un composant, React fournit des propriétés ou des accessoires en abrégé. Semblable aux attributs XML, nous transmettons les accessoires directement à un composant et pouvons ensuite utiliser les accessoires à l'intérieur du composant construit.
var Hello = function(props) { this.render = function() { return <div className="my-component">Hello {props.name}</div>; }; }; var Greeter = function() { this.render = function() { return <Hello name="there" /> } };
Cela conduit à ce que nos composants soient dans une structure arborescente, et nous ne sommes autorisés à transmettre des données que lors de la construction d'éléments enfants.
Re-rendre sur les changements
En plus des accessoires, les composants peuvent également avoir un état interne. L'exemple le plus frappant de ce comportement serait un compteur de clics qui met à jour sa valeur lorsqu'un bouton est enfoncé. Le nombre de clics lui-même serait enregistré dans l'état.
Chacun des changements d'accessoire et d'état déclenche un nouveau rendu complet du composant.
DOM virtuel
Maintenant, quand tout est restitué lorsque les accessoires ou l'état changent, comment se fait-il que React lui-même fonctionne si bien ? L'ingrédient magique est le "DOM virtuel". Chaque fois que quelque chose doit être rendu à nouveau, une représentation virtuelle du DOM mis à jour est générée. Le DOM virtuel se compose de représentations légères d'éléments modélisés d'après l'arborescence des composants, ce qui rend le processus de génération beaucoup plus efficace que la génération d'éléments DOM réels. Avant d'appliquer les modifications au DOM réel, des vérifications sont effectuées pour déterminer où exactement dans l'arborescence des composants les modifications se sont produites, un diff est créé et seules ces modifications spécifiques sont appliquées.
Premiers pas avec ce tutoriel React Native
Il y a certaines conditions préalables que les débutants devront mettre en place afin de développer pour React Native. Étant donné qu'iOS a été la première plate-forme prise en charge, et celle que nous couvrons dans ce didacticiel, nous avons besoin de macOS et Xcode, au moins la version 6.3. Node.js est également nécessaire. Ce qui aide, c'est d'installer Watchman via le gestionnaire de packages Brew avec brew install watchman
. Bien que cela ne soit pas nécessairement nécessaire, cela aide à gérer de nombreux fichiers dans notre projet React Native.
Pour installer React Native, il suffit d'installer l'application en ligne de commande React Native avec npm install -g react-native-cli
. L'appel de la commande react-native
nous aide ensuite à créer une nouvelle application React Native. L'exécution react-native init HelloWorld
crée un dossier appelé HelloWorld
dans lequel le code passe-partout peut être trouvé.
Transformer une application React
React étant la fonctionnalité clé et les principes de base issus de la bibliothèque React, examinons ce dont nous avons besoin pour transformer une application React "Hello World" minimale en une application React Native.
Nous utilisons certaines fonctionnalités ES2015 dans cet exemple de code, en particulier les classes. Il est tout à fait possible de s'en tenir à React.createClass
ou d'utiliser un formulaire de fonction similaire au modèle de module populaire.
var React = require('react'); class HelloThere extends React.Component { clickMe() { alert('Hi!'); } render() { return ( <div className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</div> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));
Étape 1 : adopter les modules CommonJS
Dans la première étape, nous devons modifier le fait que le module React doit utiliser react-native
à la place.
var React = require('react-native'); class HelloThere extends React.Component { clickMe() { alert('Hi!'); } render() { return ( <div className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</div> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));
Ce qui fait généralement partie du pipeline d'outils lors du développement d'une application Web React fait partie intégrante de React Native.
Étape 2 : Il n'y a pas de DOM
Sans surprise, il n'y a pas de DOM sur mobile. Là où nous utilisions auparavant <div />
, nous devons utiliser <View />
et là où nous utilisions <span />
, le composant dont nous avons besoin ici est <Text />
.
import React from 'react'; import {View, Text, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</View> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));
Bien qu'il soit assez pratique de mettre du texte directement dans les éléments <div />
, dans le monde natif, le texte ne peut pas être placé directement dans un <View />
. Pour cela, nous devons insérer un composant <Text />
.
import React from 'react'; import {View, Text, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View className="box" onClick={this.clickMe.bind(this)}> <Text>Hello {this.props.name}. Please click me.</Text> </View> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));
Étape 3 : Les styles en ligne sont la voie à suivre
React Native nous permet d'utiliser la modélisation Flexbox au lieu de jouer avec le float
et inline-block
que nous connaissons si bien dans le monde du Web. La chose intéressante est que React Native n'utilise pas de CSS.
import React from 'react'; import {View, Text, StyleSheet, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View style={styles.box} onClick={this.clickMe.bind(this)}> <Text>Hello {this.props.name}. Please click me.</Text> </View> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));
L'utilisation de styles en ligne semble déroutante pour les débutants. C'est similaire à la transition que les développeurs de React ont dû traverser lorsqu'ils étaient confrontés à JSX et utilisaient auparavant des moteurs de modèles comme Handlebars ou Jade.
L'idée est que nous n'avons pas de feuilles de style globalement dans la façon dont nous utilisons CSS. Nous déclarons les feuilles de style directement au niveau du composant, et nous avons donc toutes les informations dont nous avons besoin pour voir ce que fait notre composant, la mise en page qu'il crée et les styles qu'il applique.
import React from 'react'; import {Text} from 'react-native'; var Headline = function(props) { this.render = () => <Text style={headlineStyle.text}>{props.caption}</Text>; }; var headlineStyles = StyleSheet.create({ text: { fontSize: 32, fontWeight: 'bold' } }); module.exports = Headline;
Étape 4 : Gestion des événements
L'équivalent de cliquer dans des pages Web consiste à appuyer sur un élément sur l'appareil mobile. Modifions notre code pour que "l'alerte" s'affiche lorsque nous tapons sur l'élément.

import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert("Hi!") } render() { return ( <TouchableOpacity onPress={this.clickMe()}> <View style={styles.box}> <Text>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));
Au lieu que les événements soient directement disponibles sur les composants <View />
, nous devons utiliser explicitement des éléments qui déclenchent des événements, dans notre cas un événement tactile lorsque vous appuyez sur la vue. Il existe différents types de composants tactiles disponibles, chacun d'eux fournissant un retour visuel différent.
Étape 5 : Personnalisez le comportement sur les plates-formes
Il est possible de détecter sur quelle plateforme l'application React Native s'exécute, en accédant à la valeur de Platform.OS
. Disons que, dans l'exemple ci-dessus, nous voulions afficher un message d'alerte différent en fonction de la plate-forme sur laquelle nous fonctionnons. Nous pouvons le faire comme ceci :
... clickMe() { var message = ''; if(Platform.OS == 'ios') { message = 'Welcome to iOS!'; } else if(Platform.OS == 'android') { message = 'Welcome to Android!'; } Alert.alert(message); } ...
Alternativement, la méthode select
est également disponible, qui fournit une syntaxe de type switch :
… clickMe() { Alert.alert(Platform.select({ ios: 'Welcome to iOS!', android: 'Welcome to Android!' }) ); } ...
Étape 6 : Polices personnalisées et react-native link
Afin d'ajouter une police personnalisée, nous devons franchir quelques étapes. Tout d'abord, assurez-vous que le nom complet de la police et le nom du fichier de la police sont les mêmes : iOS utilisera le nom complet de la police pour récupérer la police, tandis qu'Android utilise le nom du fichier.
Ainsi, si le nom complet de votre police est myCustomFont
, assurez-vous que le nom de fichier de la police est myCustomFont.ttf
.
Après cela, nous devons créer un dossier assets et pointer npm vers celui-ci. Nous pouvons le faire en créant d'abord le dossier, sous assets/fonts
dans le répertoire racine de l'application. N'importe quel autre répertoire fera l'affaire, mais c'est le nom conventionnel utilisé pour le répertoire des polices.
Nous pouvons dire à npm où nous avons nos actifs en ajoutant une propriété Assets
sous la section d'intégration npm de React, rnpm :
"rnpm": { "Assets": [ "./assets/fonts/" ] }
Une fois que nous avons fait tout cela, nous pouvons enfin exécuter react-native link
. Cela copiera les polices dans les bons répertoires et ajoutera le xml nécessaire à info.plist sur iOS.
Une fois cela fait, nous pouvons utiliser notre police en la référençant simplement dans n'importe quelle feuille de style par son nom complet. Utilisons-le sur notre élément Text
:
import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert("Hi!") } render() { return ( <TouchableOpacity onPress={this.clickMe()}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 }, message: { fontFamily: 'myCustomFont' } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));
Étape 7 : Déplacer les choses
React Native utilise les mêmes règles que Flexbox pour la disposition des composants. Disons que nous voulions positionner notre bouton en bas de l'écran : enveloppons notre TouchableOpacity
avec un conteneur View
:
<View style={styles.container}> <TouchableOpacity onPress={this.clickMe.bind(this)}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> </View>
Et maintenant, définissons le style de container
, ainsi que les autres styles déjà définis :
container: { flex: 1, justifyContent: 'center', alignItems: 'center' }
Concentrons- alignItems
justifyContent
Ces deux propriétés contrôlent la manière dont le composant est aligné respectivement le long de son axe principal et de son axe secondaire. Par défaut, l'axe principal est l'axe vertical et l'axe secondaire est l'axe horizontal (vous pouvez modifier cela en définissant la propriété flexDirection
sur row
).
justifyContent
a six valeurs possibles sur lesquelles il peut être défini :
-
flex-start
positionnera tous les éléments ensemble, au début de la boîte englobante du composant. -
flex-end
positionnera tous les éléments à la fin. -
center
positionnera tous les éléments au centre de la boîte englobante. -
space-around
répartira les composants uniformément et centrera les composants dans leurs boîtes englobantes créées. -
space-evenly
répartira également les composants de manière uniforme, mais il essaiera de laisser un espace égal entre les composants et les autres limites. -
space-between
répartira les composants en maintenant l'espacement entre les composants adjacents égal.
alignItems
peut être défini sur quatre valeurs possibles : flex-start
, flex-end
, center
et stretch
. Les trois premiers se comportent comme ils le font pour justifyContent
, tandis que stretch
définira le composant pour qu'il occupe tout l'espace disponible le long de l'axe, de sorte que l'axe soit complètement rempli.
Donc, puisque nous voulons que notre TouchableOpacity
soit affiché en bas et centré le long de l'axe horizontal, nous pouvons changer le style comme ceci :
container: { flex: 1, justifyContent: 'flex-end', alignItems: 'center' }
Vous trouverez plus d'informations sur les valeurs justifyContent
et alignItems
ici et ici.
Étape 8 : Enregistrement de l'application
Lors du développement avec React pour le navigateur, il nous suffit de définir un point de montage, d'appeler React.render
et de laisser React faire sa magie. Dans React Native, c'est un peu différent.
import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert, Platform} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert(Platform.select({ ios: 'Welcome to iOS!', android: 'Welcome to Android!' })); } render() { return ( <View style={styles.container}> <TouchableOpacity onPress={this.clickMe.bind(this)}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> </View> ); } } var styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'flex-start', alignItems: 'center' }, box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 }, message: { fontFamily: 'myCustomFont' } }); var MainComponent = function() { this.render = function() { return <HelloThere name="Component" />; } }; AppRegistry.registerComponent('MainComponent', function() { return MainComponent; });
Nous devons enregistrer le composant pour le côté Objective-C des choses, ce qui se fait à l'aide de l'objet AppRegistry
. Le nom que nous donnons doit correspondre au nom dans le projet Xcode.
Notre application Hello World React Native a beaucoup plus de lignes de code que son homologue Web, mais d'un autre côté, React Native va un peu plus loin dans la séparation des préoccupations, notamment parce que les styles sont définis avec le composant.
En remarque, nous ne devrions pas relier la méthode clickMe
au contexte this
dans la méthode render
, surtout si notre application React (Native) devient un peu plus complexe. Il relie la méthode à chaque appel de rendu, ce qui peut devenir beaucoup. L'alternative est de lier la méthode à l'intérieur du constructeur.
Exécution de l'application
Pour exécuter l'application, nous devons remplacer le contenu du fichier index.ios.js
par le morceau de code de notre application transformée de la dernière étape. Ensuite, nous avons juste besoin d'ouvrir le projet Xcode et d'appuyer sur le gros bouton Exécuter. Tout d'abord, un terminal s'ouvrira avec le serveur React Native, puis la fenêtre du simulateur apparaîtra. Le serveur React Native crée un bundle, que l'application native va ensuite récupérer. Cela permet un cycle de développement rapide de type développement Web, où les modifications seront reflétées presque instantanément dans le simulateur.
Pour Android, il suffit d'ajouter ce qui suit à votre fichier package.json
, sous scripts
:
"android-linux": "react-native bundle --platform android --dev false --entry-file index.ios.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/ main/res && react-native run-android"
Et puis exécutez npm run android-linux
. Assurez-vous que le répertoire android/app/src/main/assets
existe au préalable.
Une fois le terminal apparu, notre application apparaîtra alors dans le simulateur. Appuyez sur CMD + D pour afficher un menu de développement. Cliquer sur la case affichera alors une alerte. La version iOS :
Et Android rend quelque chose comme ceci :
Pour la distribution, avoir une application qui pointe vers un serveur de développement local ne nous conviendrait pas. Pour cette raison, nous pouvons créer le bundle à utiliser lorsque le serveur React Native ne fonctionne pas avec la commande react-native bundle
. Dans ce cas, nous devons mettre à jour la méthode didFinishLaunchingWithOptions
de AppDelegate
pour utiliser le bundle hors ligne.
Cet exemple d'application est également disponible sur Github.
Travailler avec React Native
Une autre chose à mentionner est que nous utilisons non seulement les concepts React et JavaScript pour nos applications mobiles, mais certains des workflows auxquels les développeurs Web sont habitués sont également disponibles avec React Native. En venant du développement Web, nous sommes habitués aux outils de développement, à l'inspection des éléments et au rechargement en direct.
La façon dont React Native fonctionne est qu'il met tous nos fichiers JavaScript dans un bundle. Ce bundle est soit servi à partir d'un serveur, soit regroupé avec l'application. Le premier est incroyablement utile pour le développement dans le simulateur, car nous pouvons activer le rechargement en direct. Le menu développeur fourni par React n'est en aucun cas aussi puissant que les outils de développement Chrome, mais il offre une expérience de développeur très semblable à celle du Web avec un rechargement et un débogage en direct avec les outils de développement/débogage Chrome (ou Safari).
Les développeurs Web connaissent JSFiddle ou JSBin, un terrain de jeu en ligne pour des tests Web rapides. Il existe un environnement similaire qui nous permet d'essayer React Native dans un navigateur Web.
React Native : un choix solide et moderne
J'avais initialement suggéré une approche plus prudente de React Native. Aujourd'hui, c'est un choix mûr et solide.
L'un des gros avantages de React est qu'il n'impose rien à votre flux de travail, car il ne représente que la couche de vue. Voulez-vous définir votre propre pipeline Grunt ? Ou préférez-vous utiliser Webpack ? Et utiliserez-vous Backbone.js pour vos besoins de modèle ? Ou voulez-vous aller avec des objets JavaScript simples ? Les réponses à toutes ces questions dépendent entièrement de vous, car React n'impose aucune restriction à ces choix. Comme le site officiel l'avait dit : "Puisque React ne fait aucune hypothèse sur le reste de votre pile technologique, il est facile de l'essayer sur une petite fonctionnalité dans un projet existant."
Dans une certaine mesure, cela est également vrai pour React Native. Les développeurs mobiles peuvent intégrer React Native dans le cadre de leur application, tirer parti du flux de travail de développement inspiré du Web et choisir d'intégrer la bibliothèque à plus grande échelle si nécessaire.
En tout cas, une chose est sûre : React Native ne s'en va pas. Facebook a un énorme intérêt à avoir plusieurs applications alimentées par React Native dans les magasins d'applications. La communauté autour de React Native est énorme et continue de croître.