Gemakkelijker reageren op inheemse ontwikkeling met Expo

Expo is een verzameling hulpprogramma's die het eenvoudiger maken om native Native-apps te coderen. In deze zelfstudie laat ik je zien hoe je snel React Native apps kunt maken met Expo.

Met Expo kunnen ontwikkelaars React Native-apps maken zonder alle frustraties die gepaard gaan met het installeren en configureren van afhankelijkheden van software zoals Android Studio, Xcode of alle andere tools die nodig zijn voor het ontwikkelen en uitvoeren van een React Native app. 

In deze zelfstudie laat ik je zien hoe je een eenvoudig geheugenspel maakt met Expo. Onderweg leert u ook het volgende:

  • Hoe de tools van Expo te gebruiken. Dit omvat de CLI-, SDK- en de Expo-client-app.
  • Een React Native-app maken met Expo.

Wat is Expo?

Expo is een raamwerk voor het snel ontwikkelen van React Native apps. Het is zoals Laravel of Symphony voor PHP-ontwikkelaars, of Ruby on Rails voor Ruby-ontwikkelaars. Expo biedt een laag bovenop de React Native API's zodat ze gemakkelijker te gebruiken en te beheren zijn. Het biedt ook tools die het gemakkelijker maken om Bootstrap te gebruiken en React Native apps te testen. Ten slotte biedt het UI-componenten en -services die gewoonlijk alleen beschikbaar zijn wanneer u een extern component van Reaction Native installeert. Al deze worden beschikbaar gesteld via de Expo SDK.

Beperkingen van Expo

Voordat je verdergaat, is het belangrijk om je bewust te zijn van enkele beperkingen van Expo: 

  1. Expo-apps niet doen ondersteuning voor uitvoering van achtergrondcodes. Dit betekent dat u bijvoorbeeld geen code kunt uitvoeren die luistert naar locatieveranderingen wanneer de app wordt gesloten.
  2. Expos-apps zijn beperkt tot de native API's die door de Expo SDK worden ondersteund. Dit betekent dat als uw app een zeer specifiek use-case heeft, zoals communiceren met een Bluetooth-randapparaat, de enige optie om deze functionaliteit te implementeren, is met gewone React Native, of door native code te schrijven met een bibliotheek genaamd ExpoKit.
  3. Expo sluit je op in hun toolset. Dit betekent dat je niet gewoon de meeste geweldige tools die beschikbaar zijn voor React Native-ontwikkeling zoals commandoregelhulpmiddelen, steigers en UI-frameworks kunt installeren en gebruiken. Maar het goede is dat de Expo SDK compatibel is met gewone React Native-apps, dus je hebt geen probleem als je je app uit de Expo haalt.
  4. Stand-alone binaire bestanden van Expo-apps kunnen alleen online worden gebouwd. Expo biedt een opdrachtregelhulpprogramma genaamd Exp. Hiermee kunnen ontwikkelaars het buildproces op Expo-servers starten. Zodra het klaar is, wordt een URL verstrekt om het te downloaden .apk of .ipa het dossier. 

Zelfs met deze beperkingen is het belangrijk om in gedachten te houden dat Expo een volledig functioneel raamwerk is met veel ondersteuning voor veelgebruikte Android- of iOS-API's. Dit betekent dat je bent gedekt voor de meeste functionaliteiten die apps vaak nodig hebben. Het is dus vaak niet nodig om buiten Expo te kijken om de native functionaliteit te implementeren.

App-overzicht

De app die we gaan maken, is een geheugenspel. Je bent misschien bekend met dit type spel - de gebruiker moet bijpassende paren vinden door kaarten twee per keer om te draaien. Dit is hoe het standaardscherm eruitziet:

En zo ziet het eruit als alle paren zijn geopend:

Zodra ze het spel hebben opgelost, kan de gebruiker op de reset om de items naar hun oorspronkelijke status te resetten. Hierdoor kunnen ze het spel opnieuw beginnen.

Installatie van Expo

In tegenstelling tot gewone React Native, waar je Android Studio of Xcode en andere afhankelijkheden moet installeren en configureren, zijn er met Expo nog maar een paar stappen om te beginnen met het ontwikkelen van apps:

  1. Download en installeer Node.js. Expo is afhankelijk van het Node.js-platform voor opdrachtregelprogramma's en afhankelijkheidsbeheer.
  2. Installeer de Expo Client op uw iOS of Android apparaat. Dit wordt gebruikt om een ​​voorbeeld van de app te bekijken terwijl u deze aan het ontwikkelen bent.
  3. Installeer het opdrachtregelhulpprogramma. Hiermee kunt u een nieuw Expo-project genereren, een bouwproces starten en meer. Voer de volgende opdracht uit om het te installeren: 
npm install exp --global

Een nieuwe Expo-app maken

Nadat u alle afhankelijkheden hebt geïnstalleerd, kunt u nu een nieuwe Expo-app genereren:

exp init MemoryGame

Zodra dat is gebeurd, wordt een nieuwe map gemaakt met de naam Geheugen spel. Navigeer erin en start de ontwikkelserver:

cd MemoryGame exp start

Als alternatief kunt u ook de Expo XDE gebruiken. Hiermee kunt u Expo-apps maken en uitvoeren via een GUI. U kunt het installatieprogramma downloaden van de repository van Expo GitHub. Momenteel ondersteunt het alleen Windows en Mac. Dus als je op Ubuntu of Linux zit, is het beter om je voorlopig op de opdrachtregel te houden.

Zodra de ontwikkelserver actief is, zou u nu iets als dit moeten kunnen zien:

Dat is de QR-code die naar de live preview van het project verwijst. Open de Expo-client-app op uw telefoon en scan de code met behulp van de QR-scanner. Op dit punt zou u nu het standaardscherm moeten kunnen bekijken. Elke keer dat je slaat Besturing S in elk van de projectbestanden moet het voorbeeld automatisch opnieuw worden geladen om de wijzigingen weer te geven.

Je vindt de volledige broncode van het project op zijn GitHub-repo. Of als je de app een kans wilt geven, kun je de demo bekijken. Selecteer gewoon QR-code en scan deze op uw telefoon met behulp van de Expo-client-app.

Codering van de app

Nu zijn we klaar om de app te coderen. Laten we beginnen met een aantal UI-componenten voordat we teruggaan en het hoofdonderdeel implementeren.

Headercomponent

De kop wordt gebruikt om de titel van de app weer te geven. Maak een componenten map. Maak er binnenin een Header.js bestand en voeg het volgende toe:

import Reageren van 'reageren'; import StyleSheet, Text, View uit 'react native'; export standaardklasse Header extends React.Component render () return (  Geheugen spel  );  const styles = StyleSheet.create (header: flex: 1, flexDirection: 'column', alignSelf: 'stretch', paddingTop: 20, paddingBodom: 5, backgroundColor: '# f3f3f3', header_text: fontWeight: 'bold', fontSize: 17, textAlign: 'center');

Dit is slechts een basiscomponent React Native, met wat styling die past bij de gebruikersinterface van onze app. 

Score component

Het volgende is het onderdeel voor het weergeven van de score (componenten / Score.js):

import Reageren van 'reageren'; import StyleSheet, Text, View uit 'react native'; export standaardklasse Score breidt React.Component render () retourneren (   This.props.score  );  const styles = StyleSheet.create (score_container: flex: 1, alignItems: 'center', padding: 10, score: fontsize: 40, fontWeight: 'bold');

Nogmaals, slechts een eenvoudige weergavecomponent met een tekstweergave en een basisstijl.

Kaartcomponent

Het kaartonderdeel (componenten / Card.js) geeft de kaarten weer. Deze kaarten gebruiken pictogrammen uit de vectorpictogrammenset Expo. Dit is een van de functies die direct uit de doos komen wanneer je Expo gebruikt: het bevat iconen van icon sets zoals FontAwesome, Entypo en Ionicons. 

In de onderstaande code kun je zien dat we alleen FontAwesome gebruiken. Het heeft het pictogram dat we willen gebruiken voor het weergeven van de standaardstatus van de kaart: een vraagteken. Zoals u verderop in het hoofdonderdeel van de app zult zien, gebruiken we ook pictogrammen van Entypo en Ionicons. De verwijzing naar die pictogrambronnen wordt doorgegeven aan dit onderdeel, dus het is niet nodig om ze hier op te geven:

import Reageren van 'reageren'; import StyleSheet, Text, View, Touchable Highlight uit 'react native'; import FontAwesome uit '@ expo / vector-icons'; // gebruik FontAwesome van de expo vectorpictogrammen

Binnen in de render () methode gebruiken we alleen de bron en het pictogram die als rekwisieten worden doorgegeven als de kaart wordt geopend. Standaard wordt alleen het vraagtekenpictogram van FontAwesome weergegeven. Maar als de kaart open is, worden de pictogrambron, het pictogram en de kleur gebruikt die als rekwisieten werden doorgegeven. 

Elk van de kaarten kan worden afgeluisterd. Als u op tikt, wordt de clickCard () functie zal worden uitgevoerd, die ook wordt doorgegeven via de rekwisieten. Later zult u zien wat de functie doet, maar weet u nu dat de staat wordt bijgewerkt om het pictogram op de kaart te onthullen: 

export standaardklasse Kaartuitbreiding React.Component render () let CardSource = FontAwesome; // stel FontAwesome in als de standaard pictogrambron laat icon_name = 'question-circle'; laat icon_color = '# 393939'; if (this.props.is_open) CardSource = this.props.src; icon_name = this.props.name; icon_color = this.props.color;  terug (      ); 

Vergeet niet om de stijlen toe te voegen:

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

helpers

We zullen ook een helper-functie gebruiken genaamd shuffle (). Dit stelt ons in staat om de reeks kaarten in willekeurige volgorde te sorteren, zodat hun volgorde anders zal zijn elke keer dat het spel wordt gereset:

Array.prototype.shuffle = function () var i = this.length, j, temp; als (i == 0) dit retourneert; while (- i) j = Math.floor (Math.random () * (i + 1)); temp = dit [i]; dit [i] = dit [j]; dit [j] = temp;  stuur dit terug; 

Belangrijkste onderdeel

Het hoofdcomponent (App.js) bevat de belangrijkste app-logica en brengt alles samen. Begin met het opnemen van de React- en Expo-pakketten die we gaan gebruiken. Deze keer gebruiken we alle pictogrambronnen van vectorpictogrammen van Expo:

import Reageren van 'reageren'; importeer StyleSheet, View, Button uit 'react native'; importeer Ionicons, FontAwesome, Entypo van '@ expo / vector-icons';

Voeg vervolgens de componenten en de helper toe die we eerder hebben gemaakt:

import Header van './components/Header'; import Score van './components/Score'; kaart importeren uit './components/Card'; importeer helpers van './helpers';

Binnen de constructor maken we eerst de array die de unieke kaarten vertegenwoordigt. src is de pictogrambron, naam is de naam van het pictogram (u kunt de namen op GitHub vinden als u andere pictogrammen wilt gebruiken), en kleur is, natuurlijk, de kleur van het pictogram:

export standaardklasse App breidt React.Component constructor (props) super (rekwisieten); // bind de functies aan de klasse this.renderCards = this.renderCards.bind (this); this.resetCards = this.resetCards.bind (this); // icon sources let sources = 'fontawesome': FontAwesome, 'entypo': Entypo, 'ionicons': Ionicons; // de unieke te gebruiken pictogrammen laten kaarten = [src: 'fontawesome', naam: 'heart', kleur: 'red', src: 'entypo', naam: 'feather', kleur: '# 7d4b12 ', src:' entypo ', naam:' flashlight ', kleur:' # f7911f ', src:' entypo ', naam:' flower ', kleur:' # 37b24d ', src:' entypo ', naam:' maan ', kleur:' # ffd43b ', src:' entypo ', naam:' youtube ', kleur:' # FF0000 ', src:' entypo ', naam:' winkel ', kleur: '# 5f5f5f', src: 'fontawesome', naam: 'github', kleur: '# 24292e', src: 'fontawesome', naam: 'skype', kleur: '# 1686D9', src: 'fontawesome', naam: 'send', kleur: '# 1c7cd6', src: 'ionicons', naam: 'ios-magnet', kleur: '# d61c1c', src: 'ionicons' , naam: 'logo-facebook', kleur: '# 3C5B9B']; // volgende: voeg code toe die de kloon maakt en de kaarten in de staat instelt

Merk op dat in plaats van het direct opgeven van de src zoals FontAwesome, Entypo of Ionicons voor elk van de objecten gebruiken we de eigenschapnamen die worden gebruikt in de bronnen voorwerp. Dit komt omdat we een kopie van de reeks kaarten moeten maken om ervoor te zorgen dat elke kaart een paar heeft. Een kopie maken met behulp van matrixmethoden zoals plak() maakt een kopie van de array, maar het probleem is dat wanneer de afzonderlijke objecten in de kopie of het origineel zijn gewijzigd, beide matrices ook worden gewijzigd. 

Dit brengt ons bij de onderstaande oplossing om een ​​volledig nieuw object te maken door het te converteren kaarten array in een tekenreeks en vervolgens parseren om deze terug te zetten naar een array. Dit is de reden waarom we strings gebruiken omdat functies niet in strings kunnen worden omgezet. Vervolgens combineren we de twee om de array te maken, die alle kaarten bevat die we nodig hebben:

laat klonen = JSON.parse (JSON.stringify (kaarten)); // maak een volledig nieuwe array uit de reeks kaarten this.cards = cards.concat (clone); // combineer het origineel en de kloon

Ga vervolgens door die array en genereer voor elk een unieke ID, stel de pictogrambron in en stel deze standaard in op een gesloten status:

// voeg het ID, de bron en de standaardstatus toe voor elke kaart this.cards.map ((obj) => let id = Math.random (). toString (36) .substring (7); obj.id = id ; obj.src = sources [obj.src]; obj.is_open = false;);

Sorteer de kaarten willekeurig en stel de standaard staat in:

this.cards = this.cards.shuffle (); // sorteer de kaarten willekeurig // stel de standaard staat this.state = current_selection: [], // deze array zal een array van kaartobjecten bevatten die momenteel door de gebruiker zijn geselecteerd. Dit bevat slechts twee objecten tegelijk. selected_pairs: [], // de namen van de pictogrammen. Deze array wordt gebruikt om ze uit te sluiten van verdere selectiescore: 0, // standaard gebruikersscore-kaarten: this.cards // de geschudde kaarten

De render () methode geeft de header, kaarten, score en de knop voor het resetten van het huidige spel. Het gebruikt de renderRows () functie om de individuele kaartrijen weer te geven. Het scherm bevat zes rijen met elk vier kaarten:

render () retour (  
this.renderRows.call (this)

Hier is de code voor de renderRows () functie. Dit gebruikt de getRowContents () functie, die verantwoordelijk is voor het maken van een array van matrices met elk vier items. Hierdoor kunnen we elke rij renderen en vervolgens een andere functie gebruiken voor het renderen van kaarten voor elke iteratie van de kaart() functie:

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

Hier is de getRowContents () functie:

getRowContents (kaarten) let contents_r = []; laat inhoud = []; laat tellen = 0; cards.forEach ((item) => count + = 1; contents.push (item); if (count == 4) contents_r.push (contents) count = 0; contents = [];); return contents_r; 

Het volgende is het renderCards () functie. Dit accepteert de reeks kaartobjecten en geeft deze weer via de Kaart component. Het enige dat we hier moeten doen is de individuele eigenschappen van elk kaartobject als rekwisieten doorgeven. Dit wordt dan gebruikt om het juiste pictogram weer te geven, zoals je hebt gezien in de code voor de Kaart component. De clickCard () functie wordt ook doorgegeven als een prop. De kaart-ID wordt doorgegeven aan die functie, zodat de unieke kaart kan worden geïdentificeerd en bijgewerkt:

renderCards (kaarten) return cards.map ((kaart, index) => return (  ); ); 

Binnen in de clickCard () functie, we krijgen de details van de geselecteerde kaart en controleren of deze verder moet worden verwerkt:

clickCard (id) let selected_pairs = this.state.selected_pairs; laat current_selection = this.state.current_selection; laat score = this.state.score; // haal de index van de momenteel geselecteerde kaart op, laat index = this.state.cards.findIndex ((kaart) => return card.id == id;); laat kaarten = deze.staat.kaarten; // de kaart moet niet al geopend zijn en staat niet op de reeks kaarten waarvan de paren al zijn geselecteerd als (kaarten [index] .is_open == false && selected_pairs.indexOf (kaarten [index] .name) === - 1) // volgende: voeg code toe voor het verwerken van de geselecteerde kaart

Laten we nu de code invullen voor het afhandelen van een geselecteerde kaart. 

Eerst openen we de kaart en voegen deze toe aan de reeks momenteel geselecteerde kaarten:

kaarten [index] .is_open = true; current_selection.push (index: index, naam: kaarten [index] .name); // volgende: voeg code toe om te bepalen of de gebruiker het juiste paar heeft geselecteerd of niet

Zodra er twee items in de reeks momenteel geselecteerde kaarten zijn, controleren we of de pictogramnamen hetzelfde zijn. Als dat het geval is, betekent dit dat de gebruiker het juiste paar heeft geselecteerd. Als ze niet hetzelfde zijn, is het een onjuist paar. In dat geval sluiten we de eerste kaart die is geselecteerd en voegen we een beetje vertraging toe voordat de tweede kaart wordt gesloten. (Op deze manier kan de gebruiker het kaartpictogram zien voordat het terugkeert naar de gesloten status.)

if (current_selection.length == 2) if (current_selection [0] .name == current_selection [1] .name) score + = 1; // verhoog de score selected_pairs.push (kaarten [index] .name);  else cards [current_selection [0] .index] .is_open = false; // sluit de eerste // vertraag het sluiten van de momenteel geselecteerde kaart met een halve seconde. setTimeout (() => kaarten [index] .is_open = false; this.setState (cards: cards);, 500);  current_selection = [];  // volgende: voeg code toe om de status bij te werken

Het laatste dat we in de gebeurtenishandler click moeten doen, is de status bijwerken om de wijzigingen in de gebruikersinterface weer te geven:

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

Een gerelateerde functie is de reset event handler. Wanneer de reset Als u op de knop tikt, wordt de standaardstatus eenvoudig hersteld door alle kaarten te sluiten en te schuiven.

resetCards () // sluit alle kaarten laat kaarten = this.cards.map ((obj) => obj.is_open = false; return obj;); kaarten = kaarten.shuffle (); // re-shuffle de kaarten // update naar standaard staat this.setState (current_selection: [], selected_pairs: [], cards: cards, score: 0); 

Ten slotte voegen we een paar basisstijlen toe om onze app er goed uit te laten zien.

const styles = StyleSheet.create (container: flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', row: flex: 1, flexDirection: 'row', body: flex: 18, justifyContent: 'spatie-tussen', opvulling: 10, marginTop: 20);

Test de app

Aangezien uw Expo-ontwikkelingsserver deze hele tijd actief is geweest, moet elke wijziging naar uw mobiele apparaat worden verzonden met live herladen. Probeer de app uit en controleer of deze werkt zoals het hoort.

Conclusie

Dat is het! In deze tutorial heb je geleerd hoe je de Expo XDE gebruikt om snel een React Native app te verbinden. Expo is echt een goede manier om te beginnen met het ontwikkelen van React Native-apps, omdat het de noodzaak wegneemt om veel software te installeren die vaak een reden tot frustratie is, vooral voor beginners. Het biedt ook tools die het heel gemakkelijk maken om een ​​voorbeeld van de app te bekijken terwijl deze wordt ontwikkeld. Zorg ervoor dat u de bronnen vermeld op de Expo-website bekijkt als u meer wilt weten.

En bekijk in de tussentijd een aantal van onze andere berichten over de ontwikkeling van de React Native-app!