TSM - React Native, o alternativă viabilă sau o risipă de timp?

Eugeniu Cojocaru - Software Engineer @ Zenitech


Într-o ședință a echipei de management:

Gigel: Produsul e stabil, am implementat aproape toate funcționalitățile cerute. Ce facem acum?

Marcel: Mai știți că a fost solicitată varianta de mobil de către cei de la Today Software Magazine? Ce ați zice dacă am începe acest proiect?"

Ionuț: Programatorii noștri sunt specializați pe C# și JavaScript, nu avem buget să angajăm alți programatori… .

Marcel: Care-i treaba, moșule? Stai liniștit, cunosc eu niște băieți de la Facebook care lucrează la un produs foarte mișto numit React Native!

Gigel: Ce e aia React Native?

Marcel: Așezați-vă bine în fotolii, urmează să vă spun o poveste fascinantă!

Ce e aia React Native?

React Native este un framework open-source lansat de Meta în 2015, utilizat predominant pentru construirea aplicațiilor native folosind JavaScript. Frameworkul utilizează funcționalitățile furnizate de librăria React, ceea ce oferă avantaje programatorilor deja familiarizați cu respectiva librărie. Pe lângă opțiunea de a crea un proiect care să folosească JavaScript, se oferă și posibilitatea de a utiliza TypeScript, React Native fiind compatibil și cu acesta. Mulți giganți contemporani folosesc React Native pentru dezvoltarea aplicațiilor, nu doar Meta (Facebook, Facebook Ads Manager, Meta Quest). Printre cei mai mari putem vedea Microsoft (Microsoft Office, Microsoft Outlook, Microsoft Teams, Xbox Game Pass, Skype), Amazon (Amazon Shopping, Amazon, Alexa, Amazon Photos, Amazon Kindle, Amazon Appstore), Shopify (Shopify, Shop: All your favorite brands, Shopify Inbox, Shopify Point of Sale), dar și mulți alții. Atât datorită succesului acestui framework, cât și al comunității în creștere se pot observa noi proiecte și moduri de utilizare: React Native Windows (Messanger Desktop - deja lansată), React Native Web.

De ce aș alege React Native?

Procesul, extrem de ușor, de refolosire a codului deja existent este unul dintre cele mai mari avantaje ale frameworkului, reducând atât efortul depus pentru mentenanță cât și cel pentru development. Funcționalități, chiar module întregi, deja create pentru aplicația de React web pot fi reutilizate cu ușurință în aplicația de mobil, atât prin clasicul copy-paste cât și prin importuri, dacă repository-ul este construit sub forma unui monorepo (mai multe proiecte într-un singur repository). Datorită comunității mari și a interesului față de acest framework, există o multitudine de librării disponibile. În ultimele versiuni de React Native se remarcă extrem de bine procesul de maturizare al frameworkului, librării 3rd party mai bine scrise sunt adăugate în ansamblul de librării de bază, se adaugă suport pentru package managers populari, precum pnpm și se fixează întotdeauna buguri raportate de comunitate.

Un alt avantaj este existența deja pe piață a uneltelor, care ușurează procesul de dezvoltare al aplicațiilor în React Native, una dintre cele mai utilizate este Expo. Expo este un ecosistem de unelte open-source care oferă ajutor în toate etapele de viață ale unui proiect, de la etapa de development până la deploy și mai departe până la monitorizarea aplicației live. Dacă aplicația pe care vrem să o dezvoltăm este simplă și nu necesită multe opțiuni de personalizare, atunci recomandarea este să folosim Expo, însă dacă aplicația este foarte personalizată (vrem să avem control total asupra modulelor native și asupra opțiunilor de configurare al buildului) se recomandă folosirea React Native CLI. Programatorii au libertatea să folosească orice librărie, orice SDK sau chiar să își scrie ei propriile module native.

React? React Native? Aceeași Mărie cu altă pălărie?

Codul pentru React Native nu este sintactic diferit față de un cod pentru React clasic, programatorul își definește componente în fișiere de tip jsx/tsx pe care le utilizează apoi mai departe. Însă există o mare diferență între React și React Native: în React Native nu folosim componente de HTML pentru definirea structurii aplicației. După cum putem observa în documentația frameworkului, există deja componente predefinite care se utilizează în loculul tagurilor clasice de HTML, de exemplu în React Native nu există preamăritul, preafolositul, preadeosebitul tag div. În schimb, avem o componentă numită View care acționează aproximativ în același fel. Ea se transformă în UIView pentru iOS, android.view pentru Android sau chiar, mai exotic, în div dacă folosim React Native pentru a dezvolta o aplicație de web.

O diferență semnificativă între div și View este faptul că View-ul are deja proprietăți de stilizare predefinite: toate View-urile sunt implicit flexbox-uri, cu orientarea conținutului pe vertical. Pentru a avea un div cu aceleași proprietăți de stilizare, programatorul trebuie să scrie cod de CSS și să menționeze direcția conținutului, care este orizontal by default. În React Native stilizarea se face cu ajutorul JavaScript folosind obiecte de tip StyleSheet sau alte librării, de exemplu styled-components.

const styles = StyleSheet.create({
  container: {
    marginHorizontal: 50,
  },
  bigBlue: {
    color: 'blue',
    fontWeight: 'bold',
    fontSize: 30,
  },
});

.....

const TomatoButton = styled.Pressable`
  color: red;
  border-color: blue;
`; 

Cum funcționează mai exact React Native-ul?

Arhitectura frameworkului React Native este una multi-nivel, împărțită în: JavaScript, Bridge și Native. Până a ajunge la etapa transformării codului de JavaScript în cod nativ, există câteva etape intermediare. La nivelul JavaScript, toate fișierele JS sau TS (componente, librării, module importate, alte fișiere care conțin logica aplicației) sunt combinate într-un singur fișier de JavaScript numit JavaScript bundle - un fișier compact, bine optimizat, ușor de distribuit și executat. Bundle-ul este încărcat de aplicație la runtime. Deoarece React Native-ul folosește principiul Lazy Loading pentru a randa componentele, din bundle sunt extrase doar părțile necesare ecranului curent. De exemplu, atunci când utilizatorul ajunge pe pagina de login, React Native folosește doar codul necesar acelui ecran (componente, funcționalitate). Nivelul Bridge se comportă ca un canal de comunicare bidirecțional între nivelul JavaScript și nivelul Native. La acest nivel există trei threaduri principale: JS Thread: interpretează codul din JS bundle, folosind motorul de execuție ales de programator (JavaScriptCore sau Hermes). Este responsabil de executarea acestuia Main Thread (UI Thread): convertește componente în componente specifice platformei, aranjează componentele pe ecran în funcție de instrucțiunile primite de la Shadow Thread, gestionează interacțiunile utilizatorului (press, long press, swipe etc.) și gestionează modulele native pentru a integra funcționalitățile native (cameră, senzori, GPS etc.) Shadow Thread: transformă instrucțiunile de stilizare ale componentelor într-un format înțeles de către sistemul de operare, calculează spațiul pe ecran ocupat de componente, asigură un aspect uniform indiferent de platformă.

Nivelul Native este alcătuit din cod specific platformei (Java/Kotlin pentru Android și Objective-C/Swift pentru iOS). Acest nivel se ocupă de randarea componentelor de UI și interacțiunea cu API-urile native.

Concluzii

React Native este un framework puternic, care începe să se maturizeze și să atragă atenția comunităților. Frameworkul oferă o alternativă ușoară pentru a scrie două aplicații, pentru două platforme diferite simultan, folosind același limbaj de programare. Companii mari adoptă acest framework, construindu-și aplicații complexe cu ajutorul lui. Dar oare acesta este viitorul aplicațiilor native? Oare React Native va deveni o alternativă și pentru dezvoltarea aplicațiilor web și desktop ? Sau oare va apărea un nou competitor pe piață care va înlocui frameworkul celor de la Meta?