Le développement natif de React est plus facile avec Expo

Expo est un ensemble d'outils facilitant le codage des applications natives de React. Dans ce tutoriel, je vais vous montrer comment créer rapidement des applications natives React avec Expo..

Avec Expo, les développeurs peuvent créer des applications natives React sans toutes les frustrations liées à l'installation et à la configuration de dépendances logicielles telles qu'Android Studio, Xcode ou tous les autres outils nécessaires pour développer et exécuter une application React Native.. 

Dans ce tutoriel, je vais vous montrer comment créer un jeu de mémoire simple avec Expo. En chemin, vous apprendrez également ce qui suit:

  • Comment utiliser les outils fournis par Expo. Cela inclut la CLI, le SDK et l'application client Expo.
  • Comment créer une application React Native en utilisant Expo.

Qu'est-ce que l'Expo??

Expo est un cadre permettant de développer rapidement des applications natives React. C'est comme Laravel ou Symphony pour les développeurs PHP, ou Ruby on Rails pour les développeurs Ruby. Expo fournit une couche au-dessus des API natives de React pour faciliter leur utilisation et leur gestion. Il fournit également des outils qui facilitent l’amorçage et le test des applications natives de React. Enfin, il fournit des composants d'interface utilisateur et des services qui ne sont généralement disponibles que lorsque vous installez un composant tiers React Native. Tous sont disponibles via le SDK Expo..

Limites de l'Expo

Avant de poursuivre, il est important de connaître certaines des limites d’Expo: 

  1. Applications Expo ne pas soutenir l'exécution du code d'arrière-plan. Cela signifie que vous ne pouvez pas, par exemple, exécuter de code qui écoute les changements d'emplacement lorsque l'application est fermée..
  2. Les applications Expos sont limitées aux API natives prises en charge par le kit de développement Expo.. Cela signifie que si votre application a un cas d'utilisation très spécifique, tel que la communication avec un périphérique Bluetooth, la seule option pour implémenter de telles fonctionnalités est avec plain React Native ou en écrivant du code natif à l'aide d'une bibliothèque appelée ExpoKit..
  3. Expo vous verrouille dans leur ensemble d'outils. Cela signifie que vous ne pouvez pas simplement installer et utiliser la plupart des excellents outils disponibles pour le développement React Native, tels que les outils de ligne de commande, les échafaudeurs et les infrastructures d'interface utilisateur. Mais ce qui est bien, c’est que le SDK Expo est compatible avec les applications natives React Native, vous n’aurez donc aucun problème à éjecter votre application d’Expo..
  4. Les fichiers binaires autonomes des applications Expo ne peuvent être créés qu'en ligne. Expo fournit un outil de ligne de commande appelé Exp. Cela permet aux développeurs d'initier le processus de construction sur les serveurs de l'Expo. Une fois cela fait, une URL sera fournie pour télécharger le fichier. .apk ou .ipa fichier. 

Même avec ces limitations, il est important de garder à l'esprit qu'Expo est un cadre entièrement fonctionnel prenant largement en charge les API Android ou iOS couramment utilisées. Cela signifie que la plupart des fonctionnalités dont les applications ont généralement besoin sont couvertes. Donc, il n'est souvent pas nécessaire de regarder en dehors de l'Expo pour implémenter la fonctionnalité native.

Aperçu de l'application

L'application que nous allons créer est un jeu de mémoire. Vous êtes peut-être familiarisé avec ce type de jeu. L'utilisateur doit trouver les paires correspondantes en retournant les cartes deux à la fois. Voici à quoi ressemble l'écran par défaut:

Et voici à quoi cela ressemble une fois que toutes les paires ont été ouvertes:

Une fois le jeu résolu, l’utilisateur peut appuyer sur le bouton réinitialiser bouton pour réinitialiser les éléments à leur état initial. Cela leur permet de tout recommencer..

Installation d'Expo

Contrairement à Plain React Native, dans lequel vous devez installer et configurer Android Studio ou Xcode et d'autres dépendances, avec Expo, il ne reste que quelques étapes à suivre pour commencer à développer des applications:

  1. Télécharger et installer Node.js. Expo s'appuie sur la plate-forme Node.js pour ses outils de ligne de commande et sa gestion des dépendances.
  2. Installez Expo Client sur votre iOS ou Android dispositif. Ceci est utilisé pour prévisualiser l'application pendant que vous la développez.
  3. Installer l'outil de ligne de commande. Cela vous permet de générer un nouveau projet Expo, d'initier un processus de construction, etc. Exécutez la commande suivante pour l'installer: 
npm install exp --global

Générer une nouvelle application Expo

Une fois que vous avez installé toutes les dépendances, vous pouvez maintenant générer une nouvelle application Expo:

exp init MemoryGame

Une fois que cela est fait, il va créer un nouveau dossier appelé Jeux de mémoire. Naviguez à l'intérieur et commencez à exécuter le serveur de développement:

cd MemoryGame exp start

Alternativement, vous pouvez également utiliser Expo XDE. Cela vous permet de créer et d'exécuter des applications Expo via une interface graphique. Vous pouvez télécharger le programme d'installation à partir du dépôt Expo GitHub. Actuellement, il ne supporte que Windows et Mac. Donc, si vous êtes sur Ubuntu ou Linux, il est préférable de s'en tenir à la ligne de commande pour l'instant..

Une fois que le serveur de développement est en cours d'exécution, vous devriez maintenant pouvoir voir quelque chose comme ceci:

C'est le code QR qui pointe sur l'aperçu en direct du projet. Ouvrez l'application client Expo sur votre téléphone et scannez le code à l'aide du scanner QR. À ce stade, vous devriez maintenant pouvoir afficher l'écran par défaut. Chaque fois que vous frappez Les contrôles sur l’un des fichiers du projet, l’aperçu doit se recharger automatiquement pour refléter les modifications.

Vous pouvez trouver le code source complet du projet sur son dépôt GitHub. Ou si vous voulez essayer l'application, vous pouvez consulter la démo. Il suffit de sélectionner le code QR et de le scanner sur votre téléphone à l'aide de l'application client Expo.

Codage de l'application

Nous sommes maintenant prêts à coder l'application. Commençons par quelques composants de l'interface utilisateur avant de revenir en arrière et de mettre en œuvre le composant principal.

Composant d'en-tête

L'en-tête est utilisé pour afficher le titre de l'application. Créer un Composants dossier. À l'intérieur, créez un Header.js déposer et ajouter ce qui suit:

importer Réagir de 'réagir'; importer StyleSheet, Text, View de 'react-native'; exporter la classe par défaut Header etend React.Component render () return (  Jeux de mémoire  )  const styles = StyleSheet.create (en-tête: flex: 1, flexDirection: 'colonne', alignSelf: 'stretch', paddingTop: 20, paddingBottom: 5, backgroundColor: '# f3f3f3', header_text: fontWeight: 'bold', fontSize: 17, textAlign: 'center');

Ceci est juste un composant de base de React Native, avec un style pour correspondre à l'interface utilisateur de notre application. 

Composant Score

Ensuite vient le composant permettant d’afficher le score (composants / Score.js):

importer Réagir de 'réagir'; importer StyleSheet, Text, View de 'react-native'; exporter la classe par défaut Score étend React.Component render () return (  this.props.score  )  const styles = StyleSheet.create (score_container: flex: 1, alignItems: 'center', remplissage: 10, score: fontSize: 40, fontWeight: 'bold');

Encore une fois, juste un composant d'affichage simple avec une vue texte et un style de base.

Composant de la carte

Le composant de carte (composants / Card.js) affichera les cartes. Ces cartes utilisent des icônes du jeu d’icônes vectorielles Expo. C'est l'une des fonctionnalités qui sortent de la boîte lorsque vous utilisez Expo: elle inclut des icônes de jeux d'icônes tels que FontAwesome, Entypo et Ionicons.. 

Dans le code ci-dessous, vous pouvez voir que nous utilisons uniquement FontAwesome. Il a l'icône que nous voulons pour afficher l'état par défaut de la carte: un point d'interrogation. Comme vous le verrez plus loin dans le composant principal de l'application, nous utiliserons également des icônes de Entypo et Ionicons. La référence à ces sources d'icônes sera transmise à ce composant. Il n'est donc pas nécessaire de les spécifier ici:

importer Réagir de 'réagir'; importer StyleSheet, Text, View, TouchableHighlight à partir de 'react-native'; importer FontAwesome depuis '@ expo / vector-icons'; // utilise FontAwesome à partir des icônes vectorielles expo

À l'intérieur de rendre() En utilisant cette méthode, nous n’utilisons la source et l’icône comme accessoires que si la carte est ouverte. Par défaut, l'icône du point d'interrogation de FontAwesome sera uniquement affichée. Mais si la carte est ouverte, elle utilisera la source de l'icône, l'icône et la couleur qui ont été transmises comme accessoires.. 

Chacune des cartes peut être exploitée. Quand on tape, le clickCard () la fonction sera exécutée, qui est également transmise via les accessoires. Plus tard, vous verrez ce que la fonction fait, mais pour l'instant, sachez simplement qu'elle met à jour l'état pour révéler l'icône sur la carte: 

classe d'exportation par défaut de la carte s'étend React.Component render () let CardSource = FontAwesome; // définir FontAwesome comme source d'icônes par défaut let icon_name = 'question-circle'; let icon_color = '# 393939'; if (this.props.is_open) CardSource = this.props.src; icon_name = this.props.name; icon_color = this.props.color;  revenir (      ) 

N'oubliez pas d'ajouter les styles:

const styles = StyleSheet.create (card: flex: 1, alignItems: 'center', card_text: fontSize: 50, fontWeight: 'bold');

Aides

Nous utiliserons également une fonction d'assistance appelée mélanger (). Cela nous permet de trier le tableau de cartes dans un ordre aléatoire afin que leur ordre soit différent chaque fois que le jeu est réinitialisé:

Array.prototype.shuffle = function () var i = this.length, j, temp; if (i == 0) renvoie ceci; tandis que (- i) j = Math.floor (Math.random () * (i + 1)); temp = this [i]; ceci [i] = ceci [j]; ceci [j] = temp;  retourne ceci; 

Composant principal

Le composant principal (App.js) contient la logique principale de l'application et rassemble tout. Commencez par inclure les packages React et Expo que nous utiliserons. Cette fois, nous utilisons toutes les sources d'icônes d'icônes vectorielles Expo:

importer Réagir de 'réagir'; importer StyleSheet, View, Button de 'react-native'; importer Ionicons, FontAwesome, Entypo depuis '@ expo / vector-icons';

Ensuite, incluez les composants et l’assistant que nous avons créés précédemment:

importer l'en-tête de './components/Header'; importer Score de './components/Score'; importer une carte de './components/Card'; importer des aides de './helpers';

À l'intérieur du constructeur, nous créons d'abord le tableau qui représente les cartes uniques. src est la source de l'icône, prénom est le nom de l'icône (vous pouvez trouver les noms sur GitHub si vous voulez utiliser d'autres icônes), et Couleur est naturellement la couleur de l'icône:

classe d'exportation par défaut App étend React.Component constructeur (props) super (props); // lie les fonctions à la classe this.renderCards = this.renderCards.bind (this); this.resetCards = this.resetCards.bind (this); // icône sources let sources = 'fontawesome': FontAwesome, 'entypo': Entypo, 'ionicons': Ionicons; // les icônes uniques à utiliser permettent aux cartes = [src: 'fontawesome', nom: 'coeur', couleur: 'rouge', src: 'entypo', nom: 'plume', couleur: '# 7d4b12 ', src:' entypo ', nom:' lampe de poche ', couleur:' # f7911f ', src:' entypo ', nom:' fleur ', couleur:' # 37b24d ', src:' entypo ', nom:' lune ', couleur:' # ffd43b ', src:' entypo ', nom:' youtube ', couleur:' # FF0000 ', src:' entypo ', nom:' boutique ', color: '# 5f5f5f', src: 'fontawesome', nom: 'github', couleur: '# 24292e', src: 'fontawesome', nom: 'skype', couleur: '# 1686D9', src: 'fontawesome', nom: 'send', couleur: '# 1c7cd6', src: 'ionicons', nom: 'ios-magnet', couleur: '# d61c1c', src: 'ionicons' , nom: 'logo-facebook', couleur: '# 3C5B9B']; // next: ajoute du code créant le clone et définissant les cartes dans l'état

Notez qu'au lieu de spécifier directement le src comme FontAwesome, Entypo ou Ioniques pour chacun des objets, nous utilisons les noms de propriété utilisés dans le sources objet. En effet, nous devrons créer une copie du tableau de cartes pour que chaque carte ait une paire. Créer une copie en utilisant des méthodes de tableau telles que tranche() créera une copie du tableau, mais le problème est qu’une fois les objets individuels modifiés dans la copie ou l’original, les deux tableaux sont également modifiés.. 

Ceci nous amène à la solution ci-dessous qui consiste à créer un objet complètement nouveau en convertissant le cartes tableau dans une chaîne, puis l’analyser pour le reconvertir en tableau. C'est la raison pour laquelle nous utilisons des chaînes car les fonctions ne peuvent pas être converties en chaînes. Nous combinons ensuite les deux pour créer le tableau, qui contient toutes les cartes dont nous avons besoin:

let clone = JSON.parse (JSON.stringify (cartes)); // crée un tableau complètement nouveau à partir du tableau de cartes this.cards = cards.concat (clone); // combine l'original et le clone

Ensuite, parcourez ce tableau et générez un ID unique pour chacun, définissez la source de l'icône, puis définissez-le par défaut sur un état fermé:

// ajoute l'ID, la source et définit l'état par défaut pour chaque carte this.cards.map ((obj) => let id = Math.random (). toString (36) .substring (7); obj.id = id ; obj.src = sources [obj.src]; obj.is_open = false;);

Triez les cartes au hasard et définissez l'état par défaut:

this.cards = this.cards.shuffle (); // trie les cartes de manière aléatoire // définit l'état par défaut this.state = current_selection: [], // ce tableau contiendra un tableau d'objets de carte actuellement sélectionnés par l'utilisateur. Cela ne contiendra que deux objets à la fois. selected_pairs: [], // les noms des icônes. Ce tableau est utilisé pour les exclure des scores de sélection suivants: 0, // cartes de score utilisateur par défaut: this.cards // les cartes mélangées

le rendre() méthode affiche l’en-tête, les cartes, le score et le bouton permettant de réinitialiser la partie en cours. Il utilise le renderRows () fonction pour rendre les lignes individuelles de la carte. L'écran aura six lignes contenant quatre cartes chacune:

render () return (  
this.renderRows.call (this)

Voici le code pour le renderRows () une fonction. Cela utilise le getRowContents () fonction, qui est responsable de la création d’un tableau de tableaux contenant quatre éléments. Cela nous permet de restituer chaque ligne, puis d’utiliser une autre fonction pour restituer les cartes à chaque itération du fichier. carte() une fonction:

renderRows () let contents = this.getRowContents (this.state.cards); return contents.map ((cards, index) => return (  this.renderCards (cartes)  ) ); 

Ici se trouve le getRowContents () une fonction:

getRowContents (cartes) let content_r = []; laisser contenu = []; laisser compter = 0; cards.forEach ((item) => compte + = 1; contents.push (objet); if (compte == 4) contenus_r.push (contenu) compte = 0; contenus = [];); return contents_r; 

Suivant est le renderCards () une fonction. Ceci accepte le tableau des objets de la carte et les rend via le Carte composant. Tout ce que nous avons à faire ici est de passer les propriétés individuelles de chaque objet de carte en tant qu’accessoires. Ceci est ensuite utilisé pour restituer la bonne icône, comme vous l'avez vu dans le code du Carte composant. le clickCard () La fonction est également transmise comme accessoire. L'ID de la carte est transmis à cette fonction afin que la carte unique puisse être identifiée et mise à jour:

renderCards (cartes) return cards.map ((card, index) => return (  ) ); 

À l'intérieur de clickCard () fonction, nous obtenons les détails de la carte sélectionnée et vérifions si elle doit être traitée ultérieurement:

clickCard (id) let selected_pairs = this.state.selected_pairs; let current_selection = this.state.current_selection; laisser score = this.state.score; // récupère l'index de la carte actuellement sélectionnée let index = this.state.cards.findIndex ((card) => return card.id == id;); let cards = this.state.cards; // la carte ne devrait pas déjà être ouverte et ne figure pas dans le tableau de cartes dont les paires sont déjà sélectionnées si (cartes [index] .is_open == false && selected_pairs.indexOf (cartes [index]. nom) == - 1) // suivant: ajouter un code pour traiter la carte sélectionnée

Maintenant remplissons le code pour manipuler une carte sélectionnée. 

Tout d'abord, nous ouvrons la carte et l'ajoutons au tableau des cartes actuellement sélectionnées:

cartes [index] .is_open = true; current_selection.push (index: index, nom: cartes [index] .name); // next: ajoute un code pour déterminer si l'utilisateur a sélectionné la bonne paire ou non

Une fois que le tableau des cartes sélectionnées contient deux éléments, nous vérifions si les noms des icônes sont identiques. Si c'est le cas, cela signifie que l'utilisateur a sélectionné la bonne paire. S'ils ne sont pas identiques, la paire est incorrecte. Dans ce cas, nous fermons la première carte sélectionnée et ajoutons un peu de retard avant de fermer la deuxième carte. (Ainsi, l'utilisateur peut voir l'icône de la carte avant qu'elle ne revienne à l'état fermé.)

if (current_selection.length == 2) if (current_selection [0] .name == current_selection [1] .name) score + = 1; // incrémente la partition selected_pairs.push (cards [index] .name);  else cartes [sélection_actuelle [0] .index] .is_open = false; // ferme le premier // retarde la fermeture de la carte sélectionnée d'une demi-seconde. setTimeout (() => cartes [index] .is_open = false; this.setState (cartes: cartes);, 500);  current_selection = [];  // next: ajout du code pour la mise à jour de l'état

La dernière chose que nous devons faire dans le gestionnaire d'événements click est de mettre à jour l'état pour refléter les modifications dans l'interface utilisateur:

this.setState (score: score, cartes: cartes, current_selection: current_selection);

Une fonction associée est le gestionnaire d'événements reset. Quand le réinitialiser bouton est activé, nous restaurons simplement l’état par défaut en fermant toutes les cartes et en mélangeant.

resetCards () // ferme toutes les cartes, laissez cartes = this.cards.map ((obj) => obj.is_open = false; return obj;); cartes = cartes.shuffle (); // remanie les cartes // met à jour l'état par défaut this.setState (current_selection: [], selected_pairs: [], cards: cards, score: 0); 

Enfin, nous ajouterons quelques styles de base pour donner à notre application une belle apparence..

const styles = StyleSheet.create (conteneur: flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', ligne: flex: 1, flexDirection: 'ligne', corps: flex: 18, justifierContenu: 'espace-entre', remplissage: 10, marginTop: 20);

Testez l'application

Depuis que votre serveur de développement Expo a fonctionné pendant tout ce temps, chaque modification doit être transmise à votre appareil mobile avec un rechargement en direct. Essayez l'application et assurez-vous qu'elle fonctionne comme prévu..

Conclusion

C'est tout! Dans ce didacticiel, vous avez appris à utiliser Expo XDE pour connecter rapidement une application React Native. Expo est un très bon moyen de commencer à développer des applications React Native, car il n’est plus nécessaire d’installer beaucoup de logiciels, ce qui est souvent une source de frustration, en particulier pour les débutants. Il fournit également des outils qui facilitent la prévisualisation de l'application en cours de développement. Assurez-vous de consulter les ressources mentionnées sur le site Web de l'Expo si vous souhaitez en savoir plus..

Et en attendant, jetez un coup d'œil à certains de nos autres articles sur le développement d'applications React Native!