O scufundare rece în React Native (Tutorial pentru începători)
Publicat: 2022-03-11Când a fost anunțat React Native, primele reacții au fost copleșitor de pozitive. În mod tradițional, când ne gândim la tehnologiile web în spațiul mobil, ne vin în minte lucruri precum Apache Cordova, care ne permit să ambalăm site-uri web sau aplicații web ca aplicații pentru platforme mobile. În acest tutorial pentru începători, vom arunca o privire asupra arhitecturii React Native, a filozofiei din spatele React Native și a modului în care se deosebește de alte soluții din același spațiu. Până la sfârșitul articolului, vom fi transformat o aplicație React „Hello World” într-una React Native.
Să începem prin a spune că React Native este o tehnologie relativ nouă. A fost disponibil oficial din martie 2015, fiind în versiune beta privată de la începutul acelui an și folosit intern la Facebook pentru o perioadă înainte de aceasta. Zicala „Roma nu a fost construită într-o zi” se aplică în general și tehnologiei. Instrumente precum grunt
și platforme precum Node.js au durat ani să se maturizeze. În lumea web, lucrurile se mișcă rapid și, cu un număr imens de cadre, pachete și instrumente care apar în fiecare zi, dezvoltatorii tind să devină puțin mai sceptici și nu vor să se arunce în orice tip de hype doar pentru a realiza că au ajuns într-o situație de blocare a vânzătorului. Vom aborda ceea ce face React Native special, de ce este o tehnologie în care merită să intri și vom acoperi câteva cazuri în care nu sunt doar unicorni și curcubee.
Sub capotă
Când vorbim despre tehnologii web pe mobil, soluțiile disponibile se încadrează de obicei într-una dintre următoarele categorii.
Gruparea aplicațiilor web într-un browser web mobil
Aplicația web se află într-un browser mobil, numit de obicei WebView. Fără nicio refactorizare majoră, un site web sau o aplicație web funcționează pe dispozitivul mobil. Este posibil să fie nevoie să luăm în considerare evenimentele din browserul mobil, cum ar fi atingerea sau ascultarea modificărilor orientării dispozitivului și ecranul mai mic pentru o experiență completă a utilizatorului, dar avem o versiune mobilă funcțională cu efort minim. Cordova/PhoneGap este cea mai populară opțiune din această categorie. Din păcate, această opțiune are un mare dezavantaj: în unele cazuri, aplicațiile dezvoltate folosind Cordova sunt semnificativ mai lente decât aplicațiile native, în special pentru aplicațiile grafice grele. În alte cazuri, sistemul de operare mobil nu oferă de fapt toate caracteristicile din WebView care sunt disponibile în browserul mobil. Experiența utilizatorului poate diferi și de aplicațiile native; acest lucru se poate întâmpla din cauza aplicației sau a platformei în sine. Această problemă poate varia de la barele de defilare care nu se simt la fel până la o întârziere vizibilă la atingerea elementelor.
Compilarea la Native Technologies
O soluție complet diferită este crearea unei baze de cod native în cele din urmă. Acest lucru se întâmplă prin transformarea codului sursă original într-un alt limbaj de programare. Schimbăm performanța nativă pentru un strat de abstractizare cu unele incertitudini. În cazul soluțiilor cu sursă închisă, nici măcar nu suntem siguri ce se întâmplă sub capotă și cu ce fel de cutie neagră avem de-a face. În alte cazuri, nu suntem siguri cât de mult ne va rupe codul următoarea actualizare a sistemului de operare mobil și când vor fi disponibile remedieri sau actualizări. Un exemplu popular al acestei categorii ar fi Haxe.
Utilizarea unui strat JavaScript
Aici, folosim motorul JavaScript al mediului mobil și executăm JavaScript acolo. Controalele native sunt mapate la obiecte și funcții JavaScript, așa că atunci când trebuia să apelăm o funcție numită fancyButtonRightHere()
, un buton ar apărea pe ecran. NativeScript sau Appcelerator Titanium sunt exemple binecunoscute ale acestei categorii.
React Native ar putea fi clasificat ca ceva din a treia categorie. Pentru versiunile iOS și Android, React Native folosește JavaScriptCore sub capotă, care este motorul JavaScript implicit pe iOS. JavaScriptCore este, de asemenea, motorul JavaScript din browserele Apple Safari. Dezvoltatorii OS X și iOS pot interfața direct cu acesta, dacă doresc.
O mare diferență este că React Native rulează codul JavaScript într-un fir separat, astfel încât interfața cu utilizatorul nu se blochează, iar animațiile ar trebui să fie mătăsoase și netede.
Reacționează este caracteristica cheie
Este demn de remarcat faptul că „React” în React Native nu este pus acolo accidental. Pentru React Native, avem nevoie de o înțelegere a ceea ce oferă exact React. Următoarele concepte funcționează la fel atât în React, cât și în React Native, deși aceste exemple de cod sunt adaptate pentru a fi rulate în browser.
Punct de intrare unic de redare
Când aruncăm o privire la o componentă React simplă, primul lucru pe care îl putem observa este că componenta are o funcție de render
. De fapt, React aruncă o eroare dacă nu există nicio funcție de randare definită în interiorul componentei.
var MyComponent = function() { this.render = function() { // Render something here }; };
Lucrul special este că nu ne încurcăm cu elementele DOM aici, ci returnăm un construct bazat pe XML care reprezintă ceea ce va fi redat în DOM. Acest construct bazat pe XML se numește JSX.
var MyComponent = function() { this.render = function() { return <div className="my-component">Hello there</div>; }; };
Un transformator JSX special preia tot acel cod cu aspect XML și îl convertește în funcții. Iată cum va arăta componenta după transformare:
var MyComponent = function() { this.render = function() { return React.createElement("div", { className: "my-component" }, "Hello there"); }; };
Cel mai mare avantaj este că, aruncând o privire rapidă la componentă, știm întotdeauna ce trebuie să facă. De exemplu, o componentă <FriendList />
poate reda un număr de componente <Friend />
. Nu ne putem reda componentele în altă parte decât în interiorul funcției de render
, așa că nu există niciodată îngrijorarea că nu știm de unde provine exact componenta noastră redată.
Flux de date unidirecțional
Pentru a construi conținutul unei componente, React oferă proprietăți sau elemente de recuzită pe scurt. Similar atributelor XML, trecem elementele de recuzită direct la o componentă și apoi putem folosi elementele de recuzită în interiorul componentei construite.
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" /> } };
Acest lucru face ca componentele noastre să fie într-o structură asemănătoare arborelui și ni se permite să transmitem date numai atunci când construim elemente copil.
Redare la modificări
Pe lângă recuzită, componentele pot avea și o stare internă. Cel mai proeminent exemplu al acestui comportament ar fi un contor de clicuri care își actualizează valoarea atunci când este apăsat un buton. Numărul de clicuri în sine ar fi salvat în stat.
Fiecare dintre prop și schimbarea stării declanșează o redare completă a componentei.
DOM virtual
Acum, când totul este redat din nou când elementele de recuzită sau starea se schimbă, de ce React în sine funcționează atât de bine? Ingredientul magic este „Virtual DOM”. Ori de câte ori este nevoie de redare a ceva, este generată o reprezentare virtuală a DOM-ului actualizat. Virtual DOM constă din reprezentări ușoare ale elementelor modelate după arborele componente, făcând procesul de generare a acestora mult mai eficient decât generarea de elemente DOM reale. Înainte de a aplica modificările la DOM-ul real, se fac verificări pentru a determina unde exact în arborele componente au avut loc modificările, se creează o diferență și se aplică doar acele modificări specifice.
Noțiuni introductive cu acest tutorial React Native
Există anumite condiții preliminare pe care începătorii vor trebui să le stabilească pentru a se dezvolta pentru React Native. Deoarece iOS a fost prima platformă acceptată și cea pe care o acoperim în acest tutorial, avem nevoie de macOS și Xcode, cel puțin versiunea 6.3. Node.js este, de asemenea, necesar. Ceea ce ajută este instalarea Watchman prin managerul de pachete Brew cu brew install watchman
. Deși acest lucru nu este neapărat necesar, ajută atunci când aveți de-a face cu o mulțime de fișiere din proiectul nostru React Native.
Pentru a instala React Native, trebuie pur și simplu să instalăm aplicația de linie de comandă React Native cu npm install -g react-native-cli
. Apelarea comenzii react-native
ne ajută apoi să creăm o nouă aplicație React Native. Rularea react-native init HelloWorld
creează un folder numit HelloWorld
în care poate fi găsit codul standard.
Transformarea unei aplicații React
React fiind caracteristica cheie și principiile de bază care provin din biblioteca React, să aruncăm o privire la ceea ce avem nevoie pentru a transforma o aplicație React „Hello World” minimală într-una React Native.
Folosim unele caracteristici ES2015 în acest exemplu de cod, în special clase. Este complet fezabil să rămâneți cu React.createClass
sau să utilizați o formă de funcție similară cu modelul de modul popular.
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'));
Pasul 1: Îmbrățișați modulele CommonJS
În primul pas, trebuie să schimbăm solicitarea modulului React să folosească react-native
în schimb.
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'));
Ceea ce este de obicei o parte a conductei de instrumente atunci când se dezvoltă o aplicație web React este o parte integrantă a React Native.
Pasul 2: Nu există DOM
Nu este surprinzător că nu există DOM pe mobil. Acolo unde am folosit anterior <div />
, trebuie să folosim <View />
și unde am folosit <span />
, componenta de care avem nevoie aici este <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'));
Deși este destul de convenabil să puneți text direct în elementele <div />
, în lumea nativă textul nu poate fi pus direct într-un <View />
. Pentru asta trebuie să inserăm o componentă <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'));
Pasul 3: stilurile inline sunt calea de urmat
React Native ne permite să folosim modelarea Flexbox în loc să ne încurcăm cu float
și inline-block
care suntem atât de familiarizați în lumea web. Lucrul interesant este că React Native nu folosește 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'));
Folosirea stilurilor inline pare uluitoare pentru începători. Este similar cu tranziția prin care au trebuit să treacă dezvoltatorii React atunci când s-au confruntat cu JSX și au folosit anterior motoare de șabloane precum Handlebars sau Jade.
Ideea este că nu avem foi de stil la nivel global în modul în care folosim CSS. Declarăm foile de stil direct la nivel de componentă și astfel avem toate informațiile de care avem nevoie pentru a vedea ce face componenta noastră, aspectul pe care îl creează și stilurile pe care le aplică.
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;
Pasul 4: Gestionarea evenimentelor
Echivalentul cu a face clic pe pagini web este atingerea unui element de pe dispozitivul mobil. Să ne schimbăm codul, astfel încât „alerta” să apară când atingem elementul.

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'));
În loc ca evenimentele să fie direct disponibile pe componentele <View />
, trebuie să folosim în mod explicit elemente care declanșează evenimente, în cazul nostru un eveniment tactil atunci când apăsăm vizualizarea. Există diferite tipuri de componente tactile disponibile, fiecare dintre ele oferind un feedback vizual diferit.
Pasul 5: Personalizați comportamentul pe platforme
Este posibil să detectați pe ce platformă rulează aplicația React Native, accesând valoarea Platform.OS
. Să presupunem că, în exemplul de mai sus, am dorit să afișăm un mesaj de alertă diferit în funcție de platforma pe care rulăm. O putem face astfel:
... clickMe() { var message = ''; if(Platform.OS == 'ios') { message = 'Welcome to iOS!'; } else if(Platform.OS == 'android') { message = 'Welcome to Android!'; } Alert.alert(message); } ...
Alternativ, este disponibilă și metoda select
, care oferă o sintaxă asemănătoare comutatorului:
… clickMe() { Alert.alert(Platform.select({ ios: 'Welcome to iOS!', android: 'Welcome to Android!' }) ); } ...
Pasul 6: Fonturi personalizate și react-native link
Pentru a adăuga un font personalizat, trebuie să trecem prin niște cercuri. În primul rând, asigurați-vă că numele complet al fontului și numele fișierului fontului sunt aceleași: iOS va folosi numele complet al fontului pentru a prelua fontul, în timp ce Android folosește numele fișierului.
Deci, dacă numele complet al fontului dvs. este myCustomFont
, asigurați-vă că numele fișierului fontului este myCustomFont.ttf
.
După aceea, trebuie să creăm un folder de active și să îndreptăm către el npm. O putem face creând mai întâi folderul, sub assets/fonts
din directorul rădăcină al aplicației. Orice alt director va funcționa, dar acesta este numele convențional folosit pentru directorul de fonturi.
Putem spune npm unde avem activele prin adăugarea unei proprietăți Assets
în secțiunea de integrare npm a React, rnpm:
"rnpm": { "Assets": [ "./assets/fonts/" ] }
După ce am făcut toate acestea, putem rula în sfârșit react-native link
. Aceasta va copia fonturile în directoarele potrivite și va adăuga xml-ul necesar la info.plist pe iOS.
Odată terminat, ne putem folosi fontul doar referindu-l în orice foaie de stil după numele complet. Să-l folosim pe elementul nostru 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'));
Pasul 7: Mutarea lucrurilor
React Native folosește aceleași reguli ca Flexbox pentru aranjarea componentelor. Să presupunem că vrem să poziționăm butonul în partea de jos a ecranului: să înfășurăm TouchableOpacity
cu un container 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>
Și acum să definim stilul container
, împreună cu celelalte stiluri deja definite:
container: { flex: 1, justifyContent: 'center', alignItems: 'center' }
Să ne concentrăm pe justifyContent
și alignItems
. Aceste două proprietăți controlează modul în care componenta este aliniată de-a lungul axei sale primare și, respectiv, a axei sale secundare. În mod implicit, axa principală este cea verticală, iar axa secundară este axa orizontală (puteți modifica acest lucru setând proprietatea flexDirection
la row
).
justifyContent
are șase valori posibile la care poate fi setat:
-
flex-start
va poziționa toate elementele împreună, la începutul casetei de delimitare a componentei. -
flex-end
va poziționa toate elementele la capăt. -
center
va poziționa toate elementele în centrul casetei de delimitare. -
space-around
va răspândi componentele în mod uniform și va centra componentele în casetele de delimitare create. -
space-evenly
va răspândi și componentele uniform, dar va încerca să lase o cantitate egală de spațiu între componente și celelalte granițe. -
space-between
componentele va răspândi prin păstrarea egală a distanței dintre componentele adiacente.
alignItems
poate fi setat la patru valori posibile: flex-start
, flex-end
, center
și stretch
. Primele trei se comportă ca și pentru justifyContent
, în timp ce stretch
va seta componenta să ocupe tot spațiul disponibil de-a lungul axei, astfel încât axa să fie complet umplută.
Deci, deoarece dorim ca TouchableOpacity
să fie afișat în partea de jos și centrat de-a lungul axei orizontale, putem schimba stilul astfel:
container: { flex: 1, justifyContent: 'flex-end', alignItems: 'center' }
Mai multe informații despre valorile justifyContent
și alignItems
care le pot avea pot fi găsite aici și aici.
Pasul 8: Înregistrarea aplicației
Când dezvoltăm cu React pentru browser, trebuie doar să definim un punct de montare, să apelăm React.render
și să lăsăm React să-și facă magia. În React Native, acest lucru este puțin diferit.
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; });
Trebuie să înregistrăm componenta pentru partea Objective-C a lucrurilor, care se face folosind obiectul AppRegistry
. Numele pe care îl dăm trebuie să se potrivească cu numele din interiorul proiectului Xcode.
Aplicația noastră Hello World React Native are mult mai multe linii de cod decât omologul său web, dar, pe de altă parte, React Native duce separarea preocupărilor puțin mai departe, mai ales pentru că stilurile sunt definite cu componenta.
Ca o notă secundară, nu ar trebui să clickMe
la this
context în metoda de render
, mai ales dacă aplicația noastră React (native) devine puțin mai complexă. Reagă metoda la fiecare apel de randare, care poate deveni destul de mult. Alternativa este să legați metoda în interiorul constructorului.
Rularea aplicației
Pentru a rula aplicația, trebuie să înlocuim conținutul fișierului index.ios.js
cu fragmentul de cod al aplicației noastre transformate de la ultimul pas. Apoi trebuie doar să deschidem proiectul Xcode și să apăsăm butonul mare Run. Mai întâi, se va deschide un terminal cu serverul React Native și apoi va apărea fereastra simulatorului. Serverul React Native creează un pachet, pe care aplicația nativă îl va prelua apoi. Acest lucru permite un ciclu de dezvoltare rapidă asemănător unei dezvoltări web, în care modificările se vor reflecta aproape instantaneu în simulator.
Pentru Android, este suficient să adăugați următoarele în fișierul package.json
, sub 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"
Și apoi rulați npm run android-linux
. Asigurați-vă că directorul android/app/src/main/assets
există în prealabil.
După ce terminalul a apărut, aplicația noastră va apărea în simulator. Apăsarea CMD+D va afișa un meniu de dezvoltare. Făcând clic pe casetă, se va afișa o alertă. Versiunea iOS:
Și Android redă ceva de genul acesta:
Pentru distribuție, a avea o aplicație care indică un server de dezvoltare locală nu ne-ar funcționa. Din acest motiv, putem crea pachetul pentru utilizare atunci când serverul React Native nu rulează cu comanda react-native bundle
. În acest caz, trebuie să actualizăm metoda didFinishLaunchingWithOptions
a AppDelegate
pentru a folosi pachetul offline.
Acest exemplu de aplicație este disponibil și pe Github.
Lucrul cu React Native
Un alt lucru care merită menționat este că nu folosim doar conceptele React și JavaScript pentru aplicațiile noastre mobile, dar unele dintre fluxurile de lucru cu care sunt obișnuiți dezvoltatorii web sunt disponibile și cu React Native. Când venim de la dezvoltarea web, suntem obișnuiți să dezvoltăm instrumente, elemente de inspectare și reîncărcare live.
Modul în care funcționează React Native este că pune toate fișierele noastre JavaScript într-un pachet. Acest pachet este fie servit de pe un server, fie este livrat împreună cu aplicația. Primul este incredibil de util pentru dezvoltare în Simulator, deoarece putem activa reîncărcarea live. Meniul pentru dezvoltatori pe care React îl oferă nu este în niciun caz la fel de puternic ca Instrumentele pentru dezvoltatori Chrome, dar oferă o experiență de dezvoltator foarte asemănătoare web, cu reîncărcare și depanare live cu instrumentele de dezvoltare/depanare Chrome (sau Safari).
Dezvoltatorii web sunt familiarizați cu JSFiddle sau JSBin, un loc de joacă online pentru teste web rapide. Există un mediu similar care ne permite să încercăm React Native într-un browser web.
React Native: O alegere solidă, modernă
Inițial sugerasem o abordare mai precaută a React Native. Astăzi, este o alegere matură și solidă.
Unul dintre marile avantaje cu React este că nu se impune asupra fluxului de lucru, deoarece reprezintă doar stratul de vizualizare. Doriți să vă definiți propria conductă Grunt? Sau preferați să utilizați Webpack? Și veți folosi Backbone.js pentru nevoile dvs. de model? Sau vrei să mergi cu obiecte JavaScript simple? Răspunsurile la toate aceste întrebări depind în totalitate de dvs., deoarece React nu impune nicio restricție asupra acestor alegeri. După cum a spus site-ul oficial: „Din moment ce React nu face presupuneri cu privire la restul stivei dvs. de tehnologie, este ușor să o încercați pe o funcție mică dintr-un proiect existent.”
Într-o anumită măsură, acest lucru este valabil și pentru React Native. Dezvoltatorii de telefonie mobilă pot integra React Native ca parte a aplicației lor, pot profita de fluxul de lucru de dezvoltare inspirat de web și pot alege să integreze biblioteca la o scară mai mare, dacă este necesar.
În orice caz, un lucru este sigur: React Native nu dispare. Facebook are o miză masivă în faptul că are mai multe aplicații React Native în magazinele de aplicații. Comunitatea din jurul React Native este imensă și continuă să crească.