Cărți preferate

HTML & CSS - carte favorita
JavaScript & Jquery - carte favorita
Fullstack React - carte preferata
Clean Code - carte preferata
2021-06-23

Cum să îți structurezi o aplicație de react

React este una dintre cele mai populare librării pentru dezvoltarea de aplicații SPA (Single Page Application) și pentru mine este number one...preferata. Am lucrat de asemenea cu Angular, AngularJs și m-am jucat printre proiecte și cu Vue JS dar dintre toate tot React este preferata mea și asta din cauza faptului că e usor să lucrezi cu aceasta librarie, îți oferă flexibilitate destul de mare și ecosistemul din jurul ei este destul de dezvoltat.

Însă dacă nu ai grijă aceasta flexibilitate vine la pachet cu un potențial haos și din experiență pot să îți spun că dacă ai ajuns acolo vor începe foarte rapid să apară problemele. Așa că în acest articol voi încerca să documentez o mică soluție de structuă a aplicației astfel încât acest haos să fie ținut sub control.

Dacă nu știi să folosești react sau dacă vrei să înveți react poate că ar trebui să cauți alt articol...acesta nu te poate ajuta foarte mult cu bazele...e mai degrabă un articol pentru avansați - vorba vine - adică îți oferă o structură care după părerea mea îți poate face proiectul ușor de întreținut și de asemenea poți adăuga fără prea multe complicații funcționalități noi.

Asa ca mai departe voi discuta despre o serie de recomandări pentru momentul în care vrei să începi un nou proiect.

1. Folosește create-react-app

În momentul în care am intrat pe primul proiect construit cu ReactJS, acum aproximativ 5 sau 6 ani, din cauză că vroiam să învăț și acasă pe lângă ceea ce făceam al muncă am încercat de mai multe ori să îmi setez de unul singur o aplicație de react dar fără să am prea mare succes. Pur și simplu nu reușeam să o fac să meargă din cauză că nu aveam experiența necesară ca să îmi fac setările și configurările necesare ca să pornească. Așa că ce făceam e că mergeam pe github și căutam proiecte de react gata setate și configurate (react starter projects cred că le zicea) și începeam de acolo.

Dacă nu ai experiența necesară și nu e neapărat nevoie să-ți faci configurările singur atunci te rog să folosești acest tool: create-react-app.

Ca să îl poți instala ai nevoie de NodeJS și de npm...dacă nu știi ce sunt te a sigur că o să găsești o tonă de informații despre aceste două lucruri.

Dupa ce ți-ai instalat NodeJS și ai și npm instalat poți rula urmatoarea comanda:

npx create-react-app aplicatiameafaimoasa

Acest mic progrămel îți va instala tot ce ai nevoie pentru a începe o nouă aplicație de react fără să mai trebuiască să-ți bați capul cu tot felul de setări. Da am scris npx - nu e o greșeală. Și acest tool vine la pachet cu Node și npm și cu ajutorul lui poți rula programe de pe npmjs.com fără să trebuiască să ți le instalezi local.

2. Un pic despre structura fișierelor

După ce ți-ai creat o apicație de react dacă de duci în folderul src acesta arată ceva de genul:

Initial Structure

Nu arată rău dar proiectul e doar la început și dacă începi să creezi componente aiurea și să le pui în toate părțile îți garantez că în curând te vei trezi că nu mai știi ce se întamplă și de unde se întâmplă. Ideal ar fi ca toate componentele de react pe care le construiești să aibă o logică astfel încât atunci când vrei să le foloșeti să știi de ce vrei să faci asta. Așa că recomandarea mea (subliniez că e doar recomandarea mea pentru că pot fi de asemenea și alte structuri de fișiere mult mai bune decât ce prezint eu aici) este să ai urmatoaree structură de foldere în folderul src: components, layout, api, config, pages, resources, shared, templates.

In editorul de cod lucrurile ar trebui să arate cam așa:

Final Structure

Și acum să explic puțin și logica din spatele aceste structuri și cee ar trebui să fie pus în fiecare folder în parte.

components

În acest folder ar trebui să stea componentele de react care sunt foarte mici, independente și reutilizabile. Ca să fac o analogie mai bună în acest fișer ar trebui să stea componente care le-ai putea pune într-o librarie de genul react-boostrap sau react-material-ui, componente de genul butoane mai speciale, slidere, tabele..etc.

layout

În layout ar trebui să stea doar componenta principala de router in care îți imporți paginile și le asociezi un anumit url. În felul ăsta partea asta îți rămâne curată și organizată.

api

În folderul de api ar trebui să ai doar fișiere cu funcții care fac calluri catre BE folosind Rest. Practic aici îți construiești niște acțiuni de genul getUsers(), sau getProducts() și aceste vor fi importante unde e nevoie dar ele ar trebui să aibă locul lor separat care să fie în acest fișier.

config

În config ar trebui să îți setezi anumite chestii care sunt diferite de la calculator la calculator și de la mediul de producție la mediul de development. Și aici mă refer la url-ul care pointeaza la un anumit BE, la parola și userul bazei de date locale sau a unei baze de date remote...etc.

pages

În acest folder trebuis să locuiască doar componentele de react care vor fi pasate la routerul din layout. Și ca să le denumim practic atunci le-am putea spune pagini.

resources

Aici locuiesc imagini, icoane, svg-uri și alte lucruri de genul.

shared

În shared ar trebui să ai componente care sunt folosite de mai multe pagini și care în teorie ar trebui folosite doar în templates. Aceste componente sunt componente de genul Header, Footer, Sidebar, Menu, SpecialFooter, SpecialMenu...etc. Spun că ar trebui folosite doar în template pentru că poți avea de exemplu un header diferit de la pagina la pagina.

templates

În templates trebui să stea cumva structura de layout de la o anumita pagina. Toate componentele din templates sunt de fapt niste componente mai speciale de route create de tine astfel încât să ai flexibilitate foarte mare atunci cand vrei sa adaugi o structura nouă pentru o anumită pagina.

3. Folosește templaturi pentru rute

O problemă destul de neplăcută pe care o aveam pe unele dintre proiectele de React pe care am lucrat era faptul că de multe ori aveam nevoie de header, footer, sidebar diferite pentru anumite rute atunci când utilizatorul era logat și cumva asta ne forța să facem o gramadă verificări in fiecare pagină de interes dacă este sau nu utilizatorul logat.

Rezolvarea vine din faptul că pentru o anumită rută poți crea un template care nu este altceva decât o componentă de router împachetată cu alte componente de care ai nevoie (gen header,footer,sidebar...etc) și care primește ca și proprietăți o rută.

Mai multe poți vedea în codul de pe github în folderul de templates.

4. Separă mediul de dezvoltare de mediul de producție folosind env-cmd

De cele mai multe ori, mai ales dacă lucrezi pe un proiect mare și care este deja folosit de oameni, un proiect îl poți găsi sub două forme: dezvoltare (development) și producție (production). Asta înseamnă cu alte cuvinte că informatiile care circula prin cele doua aplicatii sunt diferite și de asemenea și bazele de date, BE, callurile către api și din acest motiv atunci când vrei să începi un proiect e bine ca această separare să fie făcută de la început. Poți folosi env-cmd un pachet de pe npmjs care îți va servi în linia de comanda variabile de mediu. Mai multe despre asta poți vedea tot așa pe github în directorul api.

5.Construiește un wrapper peste libraria de caluri catre BE

Aici o să vorbim un pic despre principiul de injectare a dependențelor (dependency injection principle) care spune că modulele superioare nu ar trebui să depindă de modulele inferioare ci ambele ar trebui să depindă de abstractizări. Ceea ce am vorbit aici ține de OOP (Object Oriented Programming) și poate e cam mult pentru un începător mai ales pe partea de FE dar findcă vorbim de react și de asemenea vorbim și despre call-uri către BE acest principiu (dependency injection) ar suna cam așa: componentele tale de react nu ar trebui să depindă în mod direct de o anumită librărie care face calluri catre BE (ex: axios, fetch) ci de abstractizări ale acestora iar aceste librari ar trebui să fie înjectate într-un wrapper care folosește această abstractizare. În felul ăsta e foarte ușor să înlocuiești o librarie cu alta și de asemenea poți foarte simplu să îți definești acțiuni specifice și descriptive pentru fiecare de apelare a backend-ului.

Pare mult și complicat ce am scris eu aici așa că uite-te un pic la exemplul de mai jos:

axios.get('/users').then(res => { 
    console.log('Afiseaza lista de utilizatori');
    console.log(res.data);
}).catch(err => {
    console.log('A aparut o eroare:');
    console.log(err);
});

axios.get('/products').then(res => { 
    console.log('Afiseaza lista de produse');
    console.log(res.data);
}).catch(err => {
    console.log('A aparut o eroare:');
    console.log(err);
});

axios.get('/bills').then(res => { 
    console.log('Afiseaza lista de facturi');
    console.log(res.data);
}).catch(err => {
    console.log('A aparut o eroare:');
    console.log(err);
});

Acum imaginează-ți că într-o aplicație de react folosești în acest fel libraria axios și la un anumit moment aceasta trebuie înlocuită. Ce este de făcut atunci? Well...o să ai o problemă mare pentru că va trebui să mergi peste tot prin cod și înlocuiești libraria cu cea nou utilizată și asta poate cauza erori, timp pierdut și frustarea.

Soluția la problema asta ar fi să folosești acest wrapper de care vorbeam și să înjectezi în el aplicatia cu caree faci calluri iar în wrapper să folosești doar versiunea abstractizată. Uită-te la următoarea bucată de cod:

const axiosInstance = axios.create({
    baseURL: 'www.backendulmeucool.com',
  });

  class RestHelper {
    constructor(instance) {
      this.instance = instance;
    }
  
    get(url) {
      return this.instance.get(url);
    }

    post(url, params) {
        return this.instance.post(url, params);
      }
    
      delete(url, params) {
        return this.instance.delete(url, params);
      }
    
      put(url, params) {
        return this.instance.put(url, params);
      }
    
      patch(url, params) {
        return this.instance.patch(url, params);
      }
  }
  
  const httpClient = new RestHelper(axiosInstance);

  const getUsers = () => httpClient.get(`/users`);
  const getProducts = () => httpClient.get(`/products`);
  const getBills = () => httpClient.get('/bills');

Ce am făcut aici este faptul că am creat o clasă RestHelper, wrapperul de care tot vorbesc și care folosește in interiorul ei o abstractizare a librariei care face calluri (instance). Deasupra am definit aceasta instanta ca fiind libraria axios pe care am injectat-o in wrapperul nostru atunci cand am creat variabila httpClient. Acum dacă am vrea să modificăm libraria ar trerbui să facem asta doar în partea de sus și să pasăm această nouă instanță la wrapper fără să mai trebuiască să căutăm prin tot codul.

6. Folosește SCSS

În react există destul de multe metode de a stiliza componentele folosid diferite tehnici și tehnologii fiecare cu avantajele și dezavantajele ei. Dacă dai o căutare pe google dupa „ways to style react components” îți vor apărea o grămadă de rezultate. Poți folosi css, scss, sass, styled components, inline styling ..etc. Dintre toate îmi place cel mai mult scss și cred că este cea mai bună opțiune pentru majoritatea proiectelor.

De ce?

În primul rând pentru că îți permite să faci embedded css ceea ce îți permite să îți aliniezi stylingul cu partea de structură html. În al doilea rând poți seta variabile, mixins, funcții, parțials lucruri care sunt foarte utile dacă vrei să faci chestii refolosibile sau vrei să faci teme.

Așa că folosește SCSS.

7. Adaugă suport pentru internaționalizare chiar de la începutul proiectului

O altă problemă...nu foarte mare din punct de vedere tehnic dar costisitoare ca timp este faptul că pe unele proiecte nu se ia în considerare de la început partea de internaționalizare (traduceri) lucru ce face ca atunci când se vrea adăugată aceată funcționalitate să dureze foarte mult timp...timp care poate ar putea fi folosit mai bine pentru dezvoltarea de alte funcționalități și de asemenea să se strice felul în care arată aplicația pentru limbi care sunt mai complicate...gen japoneza..lucru care poatee să ia din nou mult timp pentru a fi fixate.

Recomandarea ar fi ca internaționalizarea să fie luată din timp (de la începutul proiectului) în vedere și va cauza din punctul meu de vedere mult mai puține probleme.

Cam asta este tot ce am avut de zis în acest articol....poți găsi pe github lucrurile de care am vorbit in folderul de frrontend. Linkul spre acest repo îl găsești aici: https://github.com/alexPopNicolae/CollectionMaster.

Știu că acest articol are concepte mai avansate și poate chiar complicate pentru începători dar...trebuia scris. Dacă ți-a plăcut ce ai găsit pe aici nu ezita să te abonezi.

O seară frumoasă!

Ți-a plăcut acest articol? Vrei mai mult?

Dacă îți plac materialele de aici și vrei să primești mai multe articole pe email sau dacă vrei să fii la curent cu ceea ce se întîmplă în aceasta comunitate atunci nu ezita să te abonezi la newsletter.

Îți voi trimite săptămînal materiale despre web development, web design, programare și multe altele astfel încât să reușești să îți dezvolți abilitați noi care să te ajute la job sau la pasiunile tale legate de programare.

Aboneaza-te la newsletter

Daca îți plac lucrurile pe care le-ai găsit pe aici și vrei mai mult atunci nu ezita să te abonezi la newsletter și să fii la curent cu ceea ce se întîmpla pe acest blog. Îți voi trimite săptamanal noile articole publicate pe blog, tutoriale scrise și video despre programare web și alte materiale despre cum poți reuși în acest domeniu al programarii web.

Așa că lasă-ți numele și adresa de email în formularul de mai jos și te voi ține la curent.