În timp ce vă dezvoltați în React, v-ați întrebat vreodată când și de ce o componentă face() metoda este rulată? Sau când se utilizează metode mai puțin evidente ale ciclului de viață shouldComponentUpdate()?

Dacă răspunsul este da, aplicația dvs. ar putea avea probleme de performanță. Citiți și veți putea să le remediați cu ușurință.

Totul se rezumă la modul în care funcționează React sub capotă. Marea promisiune a lui React este că arde rapid la redarea elementelor de pe o pagină.

Pentru a face acest lucru, React păstrează în memorie două versiuni ale DOM:

  • versiunea DOM afișată în prezent
  • următoarea versiune a DOM care va fi afișată

Acesta compară cele două și actualizează DOM-ul afișat doar cu părțile care s-au schimbat. Acest proces se numește împăcarea copacilor. Rădăcina arborelui evaluat pentru reconciliere este o componentă care recuzită s-au schimbat.

Grozav. Acum, indiferent dacă ați planificat sau nu, aplicația dvs. web urmărește într-o oarecare măsură divizarea componentelor container / prezentare. Vedea aici și aici pentru definiții. Acest lucru înseamnă că fiecare vizualizare complexă din aplicația dvs. este formată dintr-o componentă container care deține logica și are o mulțime de afișează numai componente ca și copii.

Acesta este un model foarte bun. Dacă priviți mai atent, înseamnă că orice interacțiune a utilizatorului din vizualizare va afecta containerul în sine și va declanșa o redare a acestuia și a tuturor copiilor săi. Spuneți că aveți o listă de elemente cu un afișaj elegant de text, imagine și un buton „Adăugați la favorite” ca stea galbenă. Modelul minim pentru un element de listă ar putea fi:

product = { 
    imageUrl: '...', 
    title: '...', 
    isFavourite: false
}

Lista de favorite ar putea proveni dintr-o altă sursă de date. Indiferent, organizația componentelor dvs. arată probabil așa:

<Container>
    <ListOfElements
        elements={this.props.elements} 
        onElementChanged={this.props.onElementChanged} 
    />
</Container>

Handlerul este apelat la clicul utilizatorului și salvează partea serverului de informații (sau persistă într-un magazin sau orice altceva) și declanșează o modificare în this.props.elements.

Rezultatul unui singur clic declanșează randarea containerului și a tuturor rândurilor din listă doar pentru a actualiza o casetă de selectare.

Aici intră în joc shouldComponentUpdate (). Puteți spune React să nu redea rânduri care nu trebuie să utilizeze această metodă.

class ListItem extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        return nextProps.isFavourite != this.props.isFavourite;
    }
    ...
}

Iată un caz concret: pe un proiect de aplicație de piață, am avut o viziune de gestionare a produselor pentru vânzători. Lista avea un model „încărcați mai mult pe măsură ce utilizatorul derulează în jos” și un element de acțiuni în linie „afișează / ascunde” pentru a seta vizibilitatea fiecărui produs. Totul era în regulă atunci când vânzătorii gestionau <100 de produse în tabloul de bord. Apoi, un anumit vânzător a început să intre și să promoveze peste 300 de produse ...

A existat un decalaj de ~ 600 ms înainte ca interfața de utilizare să fie actualizată după ce un utilizator a dat clic pe pictograma „activate / disable”. Decalajul a fost vizibil cu siguranță de către utilizatorul final. Folosind Profiler Chrome am văzut că a fost nevoie de React ~ 2ms pentru a reda un singur rând. Times 300 … am ajuns la 600ms. Am adăugat verificările shouldComponentUpdate () pentru condițiile adecvate. Timpul de redare după clicul utilizatorului a scăzut sub 10 ms …

Am realizat un mic proiect care permite reproducerea acestui caz aici. Rulați-l și citiți comentariile de cod pentru a vedea cum se întâmplă magia.

Avertisment pentru utilizatorii Redux

Problema descrisă mai sus se poate întâmpla mai des dacă utilizați Redux și reselectați (sau biblioteci similare de conducte de acțiune „bazate pe magazin”).

Cu Redux și reselectare, împingeți acțiunile în magazin și conectați ascultătorii pentru a stoca modificările, și anume selectoare. Selectoarele sunt disponibile la nivel global în aplicație și pe o aplicație mare, este destul de ușor pentru multe componente să mapeze pe aceleași selectoare. Modificările aduse magazinului pot declanșa modificări ale accesoriilor și, prin urmare, sunt complet irelevante pentru unele componente.

Iată sfatul confuz: nu folosi shouldComponentUpdate () pentru a preveni randările în astfel de cazuri. Logica din interiorul shouldComponentUpdate ar trebui să analizeze doar ceea ce este relevant pentru componentă. Nu ar trebui să anticipeze niciodată contextele în care este utilizată componenta. Motivul este doar faptul că codul dvs. ar deveni rapid de întreținut.

Dacă aveți acest tip de probleme, înseamnă că structura magazinului dvs. este greșită sau selectorii nu sunt suficient de specifici. Trebuie să ajungeți la o nouă rundă de modelare.

Vă recomand acest cazan minunat instrucțiuni. Promovează încapsularea magazinului pe container de nivel înalt cu o zonă globală pentru structurile cheie de date care se întind pe întreaga aplicație. Aceasta este o abordare destul de sigură pentru a evita greșelile de modelare a magazinelor.

Mulțumesc pentru lectură! Dacă ți-a plăcut, apasă pe butonul de batere de mai jos. Ajută alte persoane să vadă povestea.