Metode de îmbunătățire și optimizare a performanței în aplicațiile React

Publicat: 2022-03-10
Rezumat rapid ↬ De când a fost introdus React, a transformat modul în care dezvoltatorii front-end construiesc aplicații web, iar DOM-ul său virtual este renumit pentru randarea eficientă a componentelor. În acest tutorial, vom discuta despre diferite metode de optimizare a performanței în aplicațiile React, precum și despre caracteristicile React pe care le putem folosi pentru a îmbunătăți performanța.

React permite aplicațiilor web să își actualizeze interfețele cu utilizatorul (UI) rapid, dar asta nu înseamnă că aplicația dvs. React medie sau mare va funcționa eficient. Performanța sa va depinde de modul în care utilizați React atunci când îl construiți și de înțelegerea dvs. asupra modului în care funcționează React și a procesului prin care componentele trăiesc în diferitele faze ale ciclului lor de viață. React oferă o mulțime de îmbunătățiri ale performanței unei aplicații web și puteți obține aceste îmbunătățiri prin diferite tehnici, funcții și instrumente.

În acest tutorial, vom discuta despre diferite metode de optimizare a performanței în aplicațiile React, precum și despre caracteristicile React pe care le putem folosi pentru a îmbunătăți performanța.

De unde să începeți optimizarea performanței într-o aplicație React?

Nu putem începe să optimizăm o aplicație fără să știm exact când și unde să o optimizăm. S-ar putea să vă întrebați „De unde începem?”

În timpul procesului inițial de randare, React construiește un arbore DOM de componente. Deci, atunci când datele se modifică în arborele DOM, dorim ca React să redea doar acele componente care au fost afectate de modificare, sărind peste celelalte componente din arbore care nu au fost afectate.

Cu toate acestea, React ar putea ajunge să redea toate componentele din arborele DOM, chiar dacă nu toate sunt afectate. Acest lucru va duce la un timp de încărcare mai lung, timp pierdut și chiar irosirea resurselor CPU. Trebuie să prevenim acest lucru să se întâmple. Deci, aici ne vom concentra efortul de optimizare.

În această situație, am putea configura fiecare componentă să redea sau să difere doar atunci când este necesar, pentru a evita risipa de resurse și timp.

Mai multe după săritură! Continuați să citiți mai jos ↓

Masurarea performantei

Nu începe niciodată procesul de optimizare a aplicației tale React pe baza a ceea ce simți. În schimb, utilizați instrumentele de măsurare disponibile pentru a analiza performanța aplicației dvs. React și pentru a obține un raport detaliat despre ceea ce ar putea încetini.

Analizarea componentelor React cu fila Performanță a Chrome

Conform documentației React, în timp ce sunteți încă în modul de dezvoltare, puteți utiliza fila „Performanță” din browserul Chrome pentru a vizualiza cum se montează, actualizează și demontează componentele React. De exemplu, imaginea de mai jos arată profilarea filei „Performanță” din Chrome și analizarea blogului meu în modul de dezvoltare.

Rezumatul profilelor de performanță
Rezumat al profilelor de performanță (previzualizare mare)

Pentru a face acest lucru, urmați acești pași:

  1. Dezactivați temporar toate extensiile, în special React Developer Tools, deoarece acestea se pot încurca cu rezultatul analizei. Puteți dezactiva cu ușurință extensiile rulând browserul în modul incognito.
  2. Asigurați-vă că aplicația rulează în modul de dezvoltare. Adică, aplicația ar trebui să ruleze pe gazda locală.
  3. Deschideți Instrumentele pentru dezvoltatori Chrome, faceți clic pe fila „Performanță”, apoi faceți clic pe butonul „Înregistrare”.
  4. Efectuați acțiunile pe care doriți să le profilați. Nu înregistrați mai mult de 20 de secunde, altfel Chrome se poate bloca.
  5. Opriți înregistrarea.
  6. Evenimentele React vor fi grupate sub eticheta „User Timing”.

Numerele din profiler sunt relative. De cele mai multe ori și componentele se vor reda mai repede în producție. Cu toate acestea, acest lucru ar trebui să vă ajute să vă dați seama când interfața de utilizare este actualizată din greșeală, precum și cât de profunde și cât de des au loc actualizările UI.

React Developer Tools Profiler

Conform documentației React, în react-dom 16.5+ și react-native 0.57+, capabilitățile îmbunătățite de profilare sunt disponibile în modul dezvoltator folosind React Developer Tools Profiler. Profiler folosește API-ul Profiler experimental de la React pentru a aduna informații de sincronizare despre fiecare componentă care este redată, pentru a identifica blocajele de performanță într-o aplicație React.

Doar descărcați React Developer Tools pentru browserul dvs. și apoi puteți utiliza instrumentul de profiler care este livrat cu acesta. Profiler-ul poate fi folosit doar fie în modul de dezvoltare, fie în versiunea de profilare de producție a React v16.5+. Imaginea de mai jos este rezumatul profilelor al blogului meu în modul de dezvoltare folosind React Developer Tools Profiler:

React Developer Tools Profiler flamegraph
React Developer Tools Profiler flamegraph (Previzualizare mare)

Pentru a realiza acest lucru, urmați acești pași:

  1. Descărcați React Developer Tools.
  2. Asigurați-vă că aplicația dvs. React este fie în modul de dezvoltare, fie în versiunea de profilare a producției a React v16.5+.
  3. Deschideți fila „Instrumente pentru dezvoltatori” din Chrome. Va fi disponibilă o nouă filă numită „Profiler”, oferită de React Developer Tools.
  4. Faceți clic pe butonul „Înregistrare” și efectuați acțiunile pe care doriți să le profilați. În mod ideal, opriți înregistrarea după ce ați efectuat acțiunile pe care doriți să le profilați.
  5. Va apărea un grafic (cunoscut sub numele de flamegraph) cu toți gestionanții de evenimente și componentele aplicației dvs. React.

Notă : Consultați documentația pentru mai multe informații.

Memorare cu React.memo()

React v16 a fost lansat cu un API suplimentar, o componentă de ordin superior numită React.memo() . Conform documentației, aceasta există doar ca o optimizare a performanței .

Numele său, „ memo ” provine de la memorare, care este practic o formă de optimizare folosită în principal pentru a accelera codul prin stocarea rezultatelor apelurilor de funcții costisitoare și returnarea rezultatului stocat ori de câte ori aceeași funcție costisitoare este apelată din nou.

Memorizarea este o tehnică de executare a unei funcții o dată, de obicei o funcție pură, și apoi de salvare a rezultatului în memorie. Dacă încercăm să executăm acea funcție din nou, cu aceleași argumente ca înainte , va returna rezultatul salvat anterior de la execuția primei funcție, fără a executa din nou funcția.

Mapând descrierea de mai sus la ecosistemul React, funcțiile menționate sunt componente React, iar argumentele sunt elemente de recuzită.

Comportamentul implicit al unei componente declarate folosind React.memo() este că se redă numai dacă elementele de recuzită din componentă s-au schimbat. Face o comparație superficială a elementelor de recuzită pentru a verifica acest lucru, dar este disponibilă o opțiune pentru a înlocui acest lucru.

React.memo() îmbunătățește performanța unei aplicații React evitând re-rendarea componentelor ale căror elemente de recuzită nu s-au schimbat sau când nu este necesară re-rendarea.

Codul de mai jos este sintaxa de bază a lui React.memo() :

 const MemoizedComponent = React.memo((props) => { // Component code goes in here })

Când să utilizați React.memo()

  • Componentă pură funcțională
    Puteți utiliza React.memo() dacă componenta dvs. este funcțională, are aceleași elemente de recuzită și redă întotdeauna aceeași ieșire. De asemenea, puteți utiliza React.memo() pe componente non-funcționale pur cu cârlige React.
  • Componenta redă des
    Puteți folosi React.memo() pentru a împacheta o componentă care se redă des.
  • Componenta este redată din nou cu aceleași elemente de recuzită
    Utilizați React.memo() pentru a împacheta o componentă care este de obicei furnizată cu aceleași elemente de recuzită în timpul redării.
  • Elemente medii spre înalte
    Folosiți-l pentru o componentă care conține un număr mediu până la mare de elemente de interfață pentru a verifica recuzita pentru egalitate.

Notă : Aveți grijă când memorați componente care folosesc elemente de recuzită ca apeluri inverse. Asigurați-vă că utilizați aceeași instanță a funcției de apel invers între randări. Acest lucru se datorează faptului că componenta părinte ar putea furniza diferite instanțe ale funcției de apel invers la fiecare randare, ceea ce va duce la întreruperea procesului de memorare. Pentru a remedia acest lucru, asigurați-vă că componenta memorată primește întotdeauna aceeași instanță de apel invers.

Să vedem cum putem folosi memorizarea într-o situație reală. Componenta funcțională de mai jos, numită „Foto”, folosește React.memo() pentru a preveni redarea din nou.

 export function Photo({ title, views }) { return ( <div> <div>Photo title: {title}</div> <div>Location: {location}</div> </div> ); } // memoize the component export const MemoizedPhoto = React.memo(Photo);

Codul de mai sus constă dintr-o componentă funcțională care afișează un div care conține un titlu de fotografie și locația subiectului în fotografie. De asemenea, memorizăm componenta creând o nouă funcție și numim-o MemoizedPhoto . Memorarea componentei foto va împiedica redarea componentei atâta timp cât elementele de recuzită, title și location sunt aceleași la randările ulterioare.

 // On first render, React calls MemoizedPhoto function. <MemoizedPhoto title="Effiel Tower" location="Paris" /> // On next render, React does not call MemoizedPhoto function, // preventing rendering <MemoizedPhoto title="Effiel Tower" location="Paris" />

Aici, React apelează funcția memorată o singură dată. Nu va reda componenta în apelul următor atâta timp cât elementele de recuzită rămân aceleași.

Gruparea și minimizarea

În aplicațiile React cu o singură pagină, putem grupa și reduce tot codul JavaScript într-un singur fișier. Acest lucru este în regulă, atâta timp cât aplicația noastră este relativ mică.

Pe măsură ce aplicația noastră React crește, gruparea și reducerea întregului cod JavaScript într-un singur fișier devine problematică, dificil de înțeles și plictisitoare. De asemenea, va afecta performanța și timpul de încărcare a aplicației noastre React, deoarece trimitem un fișier JavaScript mare către browser. Deci, avem nevoie de un proces care să ne ajute să împărțim baza de cod în diferite fișiere și să le livrăm browserului la intervale, după cum este necesar.

Într-o situație ca aceasta, putem folosi o anumită formă de grupare de active, cum ar fi Webpack, și apoi să folosim funcționalitatea sa de divizare a codului pentru a împărți aplicația noastră în mai multe fișiere.

Divizarea codului este sugerată în documentația Webpack ca un mijloc de a îmbunătăți timpul de încărcare a unei aplicații. Este, de asemenea, sugerat în documentația React pentru încărcarea leneșă (care servește doar lucrurile necesare în prezent de utilizator), care poate îmbunătăți dramatic performanța.

Webpack sugerează trei abordări generale ale împărțirii codului:

  • Puncte de intrare
    Cod împărțit manual folosind configurația de intrare.
  • Prevenirea dublării
    Utilizați SplitChunksPlugin pentru a deduplica și a împărți bucăți.
  • Importuri dinamice
    Divizarea codului prin apeluri de funcții inline în cadrul modulelor.

Beneficiile împărțirii codului

  • Divizarea codului ajută la resursele cache ale browserului și la codul care nu se schimbă des.
  • De asemenea, ajută browserul să descarce resurse în paralel, ceea ce reduce timpul general de încărcare a aplicației.
  • Ne permite să împărțim codul în bucăți care vor fi încărcate la cerere sau după cum este necesar de aplicație.
  • Menține descărcarea inițială a resurselor la prima randare relativ mică, reducând astfel timpul de încărcare a aplicației.
Procesul de grupare și minimizare
Proces de grupare și minimizare (previzualizare mare)

Structuri de date imuabile

Documentația lui React vorbește despre puterea de a nu muta datele. Orice date care nu pot fi modificate sunt imuabile. Imuabilitatea este un concept pe care programatorii React ar trebui să-l înțeleagă.

O valoare sau un obiect imuabil nu poate fi schimbat. Deci, atunci când există o actualizare, o nouă valoare este creată în memorie, lăsând-o neatinsă pe cea veche.

Putem folosi structuri de date imuabile și React.PureComponent pentru a verifica automat o schimbare complexă a stării. De exemplu, dacă starea din aplicația dvs. este imuabilă, puteți salva de fapt toate obiectele de stare într-un singur magazin cu o bibliotecă de gestionare a stării precum Redux, permițându-vă să implementați cu ușurință funcționalitatea de anulare și refacere.

Nu uitați că nu putem modifica datele imuabile odată ce sunt create.

Beneficiile structurilor de date imuabile

  • Nu au efecte secundare.
  • Obiectele de date imuabile sunt ușor de creat, testat și utilizat.
  • Ele ne ajută să scriem o logică care poate fi folosită pentru a verifica rapid actualizările în stare, fără a fi nevoie să verificăm datele din nou și din nou.
  • Ele ajută la prevenirea cuplării temporale (un tip de cuplare în care codul depinde de ordinea execuției).

Următoarele biblioteci ajută la furnizarea unui set de structuri de date imuabile:

  • imuabilitate-ajutor
    Mutați o copie a datelor fără a schimba sursa.
  • Imuabil.js
    Colecțiile de date persistente imuabile pentru JavaScript măresc eficiența și simplitatea.
  • fără sudură-imuabil
    Structurile de date imuabile pentru JavaScript devin compatibile cu matricele și obiectele JavaScript normale.
  • Reacționează-copie-scrie
    Acest lucru oferă o stare imuabilă cu un API mutabil.

Alte metode de îmbunătățire a performanței

Utilizați o versiune de producție înainte de implementare

Documentația React sugerează utilizarea versiunii de producție minimizate atunci când implementați aplicația dvs.

Reactează avertismentul „producție” din Instrumentele pentru dezvoltatori
React Developer Tools avertismentul „construcție de producție” (previzualizare mare)

Evitați funcțiile anonime

Deoarece funcțiilor anonime nu li se atribuie un identificator (prin const/let/var ), ele nu sunt persistente ori de câte ori o componentă este redată inevitabil din nou. Acest lucru face ca JavaScript să aloce memorie nouă de fiecare dată când această componentă este redată din nou, în loc să aloce o singură bucată de memorie o singură dată, ca atunci când sunt utilizate funcții numite.

 import React from 'react'; // Don't do this. class Dont extends Component { render() { return ( <button onClick={() => console.log('Do not do this')}> Don't </button> ); } } // The better way class Do extends Component { handleClick = () => { console.log('This is OK'); } render() { return ( <button onClick={this.handleClick}> Do </button> ); } }

Codul de mai sus arată două moduri diferite de a face ca un buton să efectueze o acțiune la clic. Primul bloc de cod folosește o funcție anonimă în prop onClick() , iar acest lucru ar afecta performanța. Al doilea bloc de cod folosește o funcție numită în funcția onClick() , care este modul corect în acest scenariu.

Montarea și demontarea componentelor este adesea costisitoare

Folosirea condiționalelor sau a tenariilor pentru a face să dispară o componentă (adică pentru a o demonta) nu este recomandabilă, deoarece componenta făcută să dispară va determina revopsirea și refluxarea browserului. Acesta este un proces costisitor deoarece pozițiile și geometriile elementelor HTML din document vor trebui recalculate. În schimb, putem folosi proprietățile de opacity și visibility ale CSS pentru a ascunde componenta. În acest fel, componenta va fi în continuare în DOM, dar invizibilă, fără nici un cost de performanță.

Virtualizați liste lungi

Documentația sugerează că, dacă redați o listă cu o cantitate mare de date, ar trebui să redați o mică parte a datelor din listă la un moment dat în fereastra de vizualizare vizibilă. Apoi, puteți reda mai multe date pe măsură ce lista este derulată; prin urmare, datele sunt afișate numai atunci când sunt în fereastra de vizualizare. Acest proces se numește „fereastră”. În ferestre, un mic subset de rânduri este redat la un moment dat. Există biblioteci populare pentru a face acest lucru, dintre care două sunt întreținute de Brian Vaughn:

  • fereastra de reacție
  • reacţionează-virtualizat

Concluzie

Există câteva alte metode de îmbunătățire a performanței aplicației dvs. React. Acest articol a discutat cele mai importante și eficiente metode de optimizare a performanței.

Sper că ți-a plăcut să citești acest tutorial. Puteți afla mai multe prin intermediul resurselor enumerate mai jos. Dacă aveți întrebări, lăsați-le în secțiunea de comentarii de mai jos. Voi fi bucuros să răspund la fiecare dintre ele.

Referințe și resurse aferente

  • „Optimizarea performanței”, React Docs
  • „Folosiți React.memo cu înțelepciune”, Dmitri Pavlutin
  • „Tehnici de optimizare a performanței în React”, Niteesh Yadav
  • „Imuabilitatea în reacție: nu este nimic în neregulă cu obiectele mutante”, Esteban Herrera
  • „10 moduri de a optimiza performanța aplicației React”, Chidume Nnamdi
  • „5 sfaturi pentru a îmbunătăți performanța aplicațiilor dvs. React”, William Le