Lettere Reagere Native Development With Expo

Expo er en samling verktøy som gjør det enklere å kode React native apps. I denne opplæringen skal jeg vise deg hvordan du raskt kan lage React native apps ved hjelp av Expo.

Med Expo kan utviklere lage React native apps uten alle de frustrasjonene som følger med installasjon og konfigurering av programvareavhengigheter som Android Studio, Xcode eller alle de andre verktøyene som trengs for å utvikle og kjøre en React Native app. 

I denne opplæringen skal jeg vise deg hvordan du lager et enkelt minne spill ved hjelp av Expo. Underveis lærer du også følgende:

  • Slik bruker du verktøyene fra Expo. Dette inkluderer CLI, SDK og Expo klienten appen.
  • Hvordan lage en React native app ved hjelp av Expo.

Hva er Expo?

Expo er et rammeverk for raskt å utvikle React native apps. Det er som Laravel eller Symfoni for PHP-utviklere, eller Ruby on Rails for Ruby-utviklere. Expo gir et lag på toppen av APIene for React native APIer for å gjøre dem enklere å bruke og administrere. Det gir også verktøy som gjør det enklere å starte opp og teste React native apps. Til slutt gir den brukergrensesnittkomponenter og -tjenester som vanligvis bare er tilgjengelige når du installerer en tredjeparts React Native-komponent. Alle disse er gjort tilgjengelige via Expo SDK.

Begrensninger av Expo

Før du går videre, er det viktig å være oppmerksom på noen av begrensningene i Expo: 

  1. Expo apps ikke støtte bakgrunnskode kjøring. Dette betyr at du ikke kan for eksempel kjøre kode som lytter etter endringsendringer når appen er stengt.
  2. Expos apps er begrenset til de innfødte APIer som Expo SDK støtter. Dette betyr at hvis appen din har et meget spesifikt brukstilfelle som for eksempel å kommunisere med en Bluetooth-perifer, er det eneste alternativet for å implementere slik funksjonalitet, med vanlig React Native, eller ved å skrive inn kode med et bibliotek kalt ExpoKit.
  3. Expo låser deg inn i deres verktøysett. Dette betyr at du ikke bare kan installere og bruke de fleste av de store verktøyene som er tilgjengelige for React Native-utvikling, for eksempel kommandolinjeverktøy, stillaser og brukergrensesnitt. Men det gode er at Expo SDK er kompatibel med enkle React native apps, så du vil ikke ha noe problem når du sender ut appen din fra Expo.
  4. Frittstående binarier av Expo-apper kan kun bygges online. Expo gir et kommandolinjeverktøy kalt Exp. Dette gjør det mulig for utviklere å starte byggeprosessen på Expo-servere. Når det er gjort, vil en nettadresse bli gitt for å laste ned .apk eller .ipa fil. 

Selv med disse begrensningene, er det viktig å huske på at Expo er et fullt funksjonelt rammeverk med mye støtte for vanlige Android- eller IOS-APIer. Dette betyr at du har dekket deg for de fleste funksjonene som apps vanligvis trenger. Så det er ofte ikke nødvendig å se utenfor Expo for å implementere den innfødte funksjonaliteten.

App Oversikt

Appen som vi skal lage er et minne spill. Du kan være kjent med denne typen spill - brukeren må finne matchende par ved å vri over kort to om gangen. Slik ser standardskjermbildet ut:

Og slik ser det ut når alle parene har blitt åpnet:

Når de har løst spillet, kan brukeren trykke på tilbakestille knappen for å tilbakestille elementene til sin opprinnelige tilstand. Dette gjør at de kan starte spillet hele tiden igjen.

Installere Expo

I motsetning til vanlig React Native der du må installere og konfigurere Android Studio eller Xcode og andre avhengigheter, er det bare noen få trinn å følge med Expo for å begynne å utvikle apper:

  1. nedlasting og installer node.js. Expo er avhengig av Node.js-plattformen for kommandolinjeverktøy og avhengighetsadministrasjon.
  2. Installer Expo Client på din iOS eller Android enhet. Dette brukes til å forhåndsvise appen mens du utvikler den.
  3. Installer kommandolinjeverktøyet. Dette lar deg generere et nytt Expo-prosjekt, starte en byggeprosess og mer. Kjør følgende kommando for å installere den: 
npm installere exp - global

Genererer en ny Expo App

Når du har installert alle avhengighetene, kan du nå generere en ny Expo-app:

exp init MemoryGame

Når det er gjort, vil det opprette en ny mappe som heter MemoryGame. Naviger inne i det og begynne å kjøre utviklingsserveren:

cd MemoryGame exp start

Alternativt kan du også bruke Expo XDE. Dette lar deg opprette og kjøre Expo-apper via en GUI. Du kan laste ned installasjonsprogrammet fra Expo GitHub repo. I øyeblikket støtter den bare Windows og Mac. Så hvis du er på Ubuntu eller Linux, er det bedre å holde fast på kommandolinjen for nå.

Når utviklingsserveren kjører, bør du nå kunne se noe slikt:

Det er QR-koden som peker på det levende forhåndsvisning av prosjektet. Åpne Expo klient-appen på telefonen din og skann koden ved hjelp av QR-skanneren. På dette tidspunktet bør du nå kunne se standardskjermbildet. Hver gang du treffer Kontroll-S På en av prosjektfilene, bør forhåndsvisning automatisk lades opp for å gjenspeile endringene.

Du finner full kilden til prosjektet på GitHub repo. Eller hvis du vil gi appen en prøve, kan du sjekke ut demoen. Bare velg QR-kode, og skann den på telefonen ved hjelp av Expo-klient-appen.

Koding av appen

Nå er vi klare til å kode appen. La oss begynne med noen UI-komponenter før vi går tilbake og implementerer hovedkomponenten.

Header Component

Overskriften brukes til å vise tittelen på appen. Lage en komponenter mappe. Inne i det, opprett en Header.js fil og legg til følgende:

Import Reakt fra 'reagere'; importer StyleSheet, Text, View fra 'react-native'; eksporter standard klasse Header strekker React.Component render () return (  MemoryGame  );  style styles = StyleSheet.create (header: flex: 1, flexDirection: 'column', alignSelf: 'stretch', paddingTop: 20, paddingBottom: 5, backgroundColor: '# f3f3f3', header_text: fontWeight: fet skrift, fontSize: 17, textAlign: 'senter');

Dette er bare en grunnleggende React Native-komponent, med noen styling som samsvarer med brukergrensesnittet i appen vår. 

Score komponent

Neste er komponenten for å vise poengsummen (komponenter / Score.js):

Import Reakt fra 'reagere'; importer StyleSheet, Text, View fra 'react-native'; eksporter standard klasse Score utvider React.Component render () return (   This.props.score  );  const styles = StyleSheet.create (score_container: flex: 1, alignItems: 'center', polstring: 10, score: fontSize: 40, fontWeight: 'bold');

Igjen, bare en enkel skjermkomponent med tekstvisning og noen grunnleggende styling.

Kortkomponent

Kortkomponenten (komponenter / Card.js) vil vise kortene. Disse kortene bruker ikoner fra Expo-vektorikonet. Dette er en av funksjonene som kommer rett ut av boksen når du bruker Expo: den inneholder ikoner fra ikonsett som FontAwesome, Entypo og Ionicons. 

I koden nedenfor kan du se at vi bare bruker FontAwesome. Den har ikonet som vi vil ha for å vise kortets standardstatus: et spørsmålstegn. Som du vil se senere i hovedappkomponenten, bruker vi også ikoner fra Entypo og Ionicons. Henvisningen til disse ikonkildene vil bli sendt til denne komponenten, så det er ikke nødvendig å spesifisere dem her:

Import Reakt fra 'reagere'; importer StyleSheet, Text, View, TouchableHighlight fra 'react-native'; importer FontAwesome fra '@ expo / vector-icons'; // bruk FontAwesome fra expo-vektorikonene

Inne i render () Metode, vi bruker bare kilden og ikonet som passasjer hvis rekvisita er åpnet. Som standard vil det bare vise spørsmålstegnikonet fra FontAwesome. Men hvis kortet er åpent, vil det bruke ikonkilden, ikonet og fargen som ble passert som rekvisitter. 

Hvert av kortene kan tappes. Når tappet, clickCard () funksjonen vil bli kjørt, som også sendes via rekvisitter. Senere ser du hva funksjonen gjør, men for nå, bare vet at den oppdaterer staten for å avsløre ikonet på kortet: 

eksporter standard klasse-kort strekker seg React.Component render () let CardSource = FontAwesome; // sett FontAwesome som standardikonkilden la icon_name = 'question-circle'; la icon_color = '# 393939'; hvis (this.props.is_open) CardSource = this.props.src; icon_name = this.props.name; icon_color = this.props.color;  komme tilbake (      ); 

Ikke glem å legge til stilene:

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

Hjelpere

Vi bruker også en hjelpefunksjon kalt tilfeldig rekkefølge(). Dette gjør at vi kan sortere rekke av kort i tilfeldig rekkefølge, slik at bestillingen deres vil være forskjellig hver gang spillet er nullstilt:

Array.prototype.shuffle = function () var i = this.length, j, temp; hvis (i == 0) returnere dette; mens (- i) j = Math.floor (Math.random () * (i + 1)); temp = dette [i]; dette [i] = dette [j]; denne [j] = temp;  returner dette 

Hovedkomponent

Hovedkomponenten (App.js) inneholder hovedapplogikken og bringer alt sammen. Begynn med å inkludere React and Expo-pakker som vi skal bruke. Denne gangen bruker vi alle ikonkildene fra Expo-vektorikonene:

Import Reakt fra 'reagere'; importer StyleSheet, View, Button fra 'react-native'; importer Ionicons, FontAwesome, Entypo fra '@ expo / vector-icons';

Deretter inkluderer du komponentene og hjelperen som vi opprettet tidligere:

Importer header fra './components/Header'; importer poeng fra './components/Score'; Importkort fra './components/Card'; importere hjelpere fra './helpers';

Inne i konstruktøren lager vi først oppstillingen som representerer de unike kortene. src er ikonkilden, Navn er navnet på ikonet (du kan finne navnene på GitHub hvis du vil bruke andre ikoner), og farge er naturligvis fargen på ikonet:

eksporter standard klasse App strekker seg React.Component constructor (rekvisitter) super (rekvisitter); // binde funksjonene til klassen this.renderCards = this.renderCards.bind (dette); this.resetCards = this.resetCards.bind (dette); // ikon kilder la kilder = 'fontawesome': FontAwesome, 'entypo': Entypo, 'ionicons': Ionicons; // de unike ikonene som skal brukes, la kort = [src: 'fontawesome', navn: 'hjerte', farge: 'rød', src: 'entypo', navn: 'fjær', farge: '# 7d4b12 ', src:' entypo ', navn:' lommelykt ', farge:' # f7911f ', src:' entypo ', navn:' blomst ', farge:' # 37b24d ', src:' entypo ', navn:' moon ', farge:' # ffd43b ', src:' entypo ', navn:' youtube ', farge:' # FF0000 ', src:' entypo ', navn:' butikk ' farge: '# 5f5f5f', src: 'fontawesome', navn: 'github', farge: '# 24292e', src: 'fontawesome', navn: 'skype', farge: '# 1686D9' src: 'fontawesome', navn: 'send', farge: '# 1c7cd6', src: 'ionicons', navn: 'ios-magnet', farge: '# d61c1c', src: 'ionicons' , navn: 'logo-facebook', farge: '# 3C5B9B']; // neste: legg til kode som lager klonen og angi kortene i staten

Legg merke til at i stedet for direkte å spesifisere src som FontAwesome, Entypo eller Ionicons For hver av objektene bruker vi egenskapsnavnene som brukes i kilder gjenstand. Dette skyldes at vi må lage en kopi av en rekke kort for at hvert kort skal ha et par. Opprette en kopi ved hjelp av matrise metoder som skjære() vil lage en kopi av arrayet, men problemet er at når de enkelte objektene er endret i enten kopien eller originalen, blir begge arrayene også endret. 

Dette bringer oss til løsningen nedenfor som skal skape et helt nytt objekt ved å konvertere kort array inn i en streng og deretter analysere den for å konvertere den tilbake til en matrise. Dette er grunnen til at vi bruker strenge siden funksjoner ikke kan konverteres til strenge. Vi kombinerer de to for å komme opp med matrisen, som inneholder alle kortene vi trenger:

la klone = JSON.parse (JSON.stringify (kort)); // lage en helt ny matrise fra mengden kort this.cards = cards.concat (klone); // kombinere originalen og klonen

Deretter går du gjennom det arrayet og genererer en unik ID for hver enkelt, sett ikonkilden, og sett den deretter til en lukket tilstand som standard:

// legg til ID, kilde og angi standardstatus for hvert kort this.cards.map ((obj) => let id = Math.random (). toString (36) .substring (7); obj.id = id ; obj.src = kilder [obj.src]; obj.is_open = false;);

Sorter kortene tilfeldig og angi standardstatus:

this.cards = this.cards.shuffle (); // sorter kortene tilfeldig // angi standardstatus this.state = current_selection: [], // dette arrayet vil inneholde en rekke kortobjekter som for øyeblikket er valgt av brukeren. Dette vil bare inneholde to objekter av gangen. selected_pairs: [], // navnene på ikonene. Denne gruppen brukes til å ekskludere dem fra ytterligere utvalgspoeng: 0, // standardbruker scorekort: this.cards // de blandede kortene

De render () Metode gjør overskriften, kortene, poengsummen og knappen for å tilbakestille gjeldende spill. Det bruker den renderRows () funksjon for å gjengi de enkelte kortrader. Skjermen vil ha seks rader med fire kort hver:

gjengivelse () retur (  
this.renderRows.call (dette)

Her er koden for renderRows () funksjon. Dette bruker getRowContents () funksjon, som er ansvarlig for å lage en rekke arrays med fire elementer hver. Dette tillater oss å gjengi hver rad, og deretter bruke en annen funksjon for gjengivelseskort for hver iterasjon av kart() funksjon:

renderRows () la innhold = this.getRowContents (this.state.cards); returnere content.map ((kort, indeks) => retur (  this.renderCards (kort)  ); ); 

Her er getRowContents () funksjon:

getRowContents (kort) let content_r = []; la innholdet = []; la telle = 0; cards.forEach ((item) => count + = 1; content.push (element); hvis (telle == 4) content_r.push (innhold) telle = 0; innhold = [];); returner content_r; 

Neste er renderCards () funksjon. Dette aksepterer rekke kartobjekter og gjør dem via Kort komponent. Alt vi trenger å gjøre her er å passere de enkelte egenskapene til hvert kortobjekt som rekvisitter. Dette brukes til å gjengi det riktige ikonet, som du har sett i koden for Kort komponent. De clickCard () funksjonen er også bestått som en prop. Kort-IDen overføres til den funksjonen slik at det unike kortet kan identifiseres og oppdateres:

renderCards (kort) return cards.map ((kort, indeks) => return (  ); ); 

Inne i clickCard () funksjon, får vi detaljene for det valgte kortet og sjekker om det skal behandles videre:

clickCard (id) la selected_pairs = this.state.selected_pairs; la current_selection = this.state.current_selection; la score = this.state.score; // hente indeksen for det valgte kortet, let index = this.state.cards.findIndex ((kort) => return card.id == id;); la kort = this.state.cards; // kortet skal ikke allerede åpnes og er ikke på utvalg av kort hvis par allerede er valgt hvis (kort [indeks] .is_open == false && selected_pairs.indexOf (kort [index] .name) === - 1) // neste: legg til kode for behandling av det valgte kortet

La oss nå fylle ut koden for å håndtere et valgt kort. 

Først åpner vi kortet og legger det til i utvalg av valgte kort:

kort [index] .is_open = true; current_selection.push (index: index, navn: kort [index] .name); // neste: legg til kode for å bestemme om brukeren har valgt riktig par eller ikke

Når det er to elementer i en rekke utvalgte kort, kontrollerer vi om ikonnavnene er de samme. Hvis de er så betyr det at brukeren har valgt riktig par. Hvis de ikke er det samme, er det et feil par. I så fall lukker vi det første kortet som ble valgt, og deretter legger du litt forsinkelse før du lukker det andre kortet. (På denne måten kan brukeren se kortikonet før det går tilbake til lukket tilstand.)

hvis (current_selection.length == 2) if (current_selection [0] .name == current_selection [1] .name) score + = 1; // øke poengsummen selected_pairs.push (kort [index] .name);  ellers kort [current_selection [0] .index] .is_open = false; // lukk den første // forsinkelsen lukker det valgte kortet med et halvt sekund. setTimeout (() => kort [indeks] .is_open = false; this.setState (kort: kort);, 500);  current_selection = [];  // neste: legg til kode for oppdatering av staten

Det siste vi må gjøre i klikkhendelsesbehandleren er å oppdatere staten for å gjenspeile endringene i brukergrensesnittet:

this.setState (score: score, kort: kort, nåværende_seleksjon: nåværende_seleksjon);

En relatert funksjon er tilbakestill hendelsesbehandleren. Når tilbakestille knappen er tappet, vi gjenoppretter bare standardstatusen ved å lukke alle kortene og shuffle.

resetCards () // lukk alle kort la kort = this.cards.map ((obj) => obj.is_open = false; return obj;); kort = cards.shuffle (); // re-shuffle kortene // oppdatere til standardstatus this.setState (current_selection: [], selected_pairs: [], cards: cards, score: 0); 

Til slutt legger vi til noen grunnleggende stiler for å få appen til å se bra ut.

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

Test appen

Siden din Expo-utviklingsserver har kjørt denne hele tiden, bør alle endringer skyves til mobilenheten med live reloading. Prøv appen og sørg for at den fungerer som den skal.

Konklusjon

Det er det! I denne opplæringen har du lært hvordan du bruker Expo XDE for raskt å koble til en React Native app. Expo er en veldig god måte å begynne å utvikle React native apps fordi det fjerner behovet for å installere mye programvare som ofte er en årsak til frustrasjon, spesielt for nybegynnere. Det gir også verktøy som gjør det veldig enkelt å forhåndsvise appen mens den blir utviklet. Pass på å sjekke ut ressursene som er nevnt på Expo-nettstedet hvis du vil lære mer.

Og i mellomtiden, ta en titt på noen av våre andre innlegg om React Native app utvikling!