Apgūstiet React saskaņošanas procesu. Uzziniet, kā pareiza 'key' rekvizīta lietošana optimizē sarakstu renderēšanu, novērš kļūdas un uzlabo aplikācijas veiktspēju.
Veiktspējas atslēgšana: Padziļināta React saskaņošanas atslēgu izpēte sarakstu optimizācijai
Mūsdienu tīmekļa izstrādes pasaulē ir ļoti svarīgi izveidot dinamiskas lietotāja saskarnes, kas ātri reaģē uz datu izmaiņām. React ar savu uz komponentēm balstīto arhitektūru un deklaratīvo dabu ir kļuvis par globālu standartu šo saskarņu veidošanai. React efektivitātes pamatā ir process, ko sauc par saskaņošanu (reconciliation), kas ietver virtuālo DOM. Tomēr pat jaudīgākos rīkus var izmantot neefektīvi, un bieža joma, kurā gan jauni, gan pieredzējuši izstrādātāji kļūdās, ir sarakstu renderēšana.
Jūs, visticamāk, neskaitāmas reizes esat rakstījis kodu, piemēram, data.map(item => <div>{item.name}</div>)
. Tas šķiet vienkārši, gandrīz triviāli. Tomēr aiz šīs vienkāršības slēpjas kritisks veiktspējas apsvērums, kas, ja to ignorē, var novest pie lēnām lietojumprogrammām un mulsinošām kļūdām. Risinājums? Mazs, bet varens rekvizīts (prop): key
.
Šis visaptverošais ceļvedis jūs aizvedīs padziļinātā React saskaņošanas procesa un atslēgu neaizstājamās lomas sarakstu renderēšanā izpētē. Mēs izpētīsim ne tikai 'ko', bet arī 'kāpēc' — kāpēc atslēgas ir būtiskas, kā tās pareizi izvēlēties, un kādas ir būtiskas sekas, ja tās tiek izvēlētas nepareizi. Beigās jums būs zināšanas, lai rakstītu veiktspējīgākas, stabilākas un profesionālākas React lietojumprogrammas.
1. nodaļa: React saskaņošanas un virtuālā DOM izpratne
Pirms mēs varam novērtēt atslēgu nozīmi, mums vispirms ir jāsaprot pamatmehānisms, kas padara React ātru: saskaņošana, ko nodrošina virtuālais DOM (VDOM).
Kas ir virtuālais DOM?
Tieša mijiedarbība ar pārlūkprogrammas dokumenta objekta modeli (DOM) ir skaitļošanas ziņā dārga. Katru reizi, kad kaut ko maināt DOM — piemēram, pievienojat mezglu, atjaunināt tekstu vai maināt stilu — pārlūkprogrammai ir jāveic ievērojams darba apjoms. Var būt nepieciešams pārrēķināt stilus un izkārtojumu visai lapai, process, kas pazīstams kā "reflow" un "repaint". Sarežģītā, uz datiem balstītā lietojumprogrammā biežas tiešas DOM manipulācijas var ātri samazināt veiktspēju līdz minimumam.
React piedāvā abstrakcijas slāni, lai to atrisinātu: virtuālo DOM. VDOM ir viegla, atmiņā esoša reālā DOM reprezentācija. Uztveriet to kā savas lietotāja saskarnes projektu. Kad jūs liekat React atjaunināt UI (piemēram, mainot komponentes stāvokli), React nekavējoties neaiztiek reālo DOM. Tā vietā tas veic šādas darbības:
- Tiek izveidots jauns VDOM koks, kas atspoguļo atjaunināto stāvokli.
- Šis jaunais VDOM koks tiek salīdzināts ar iepriekšējo VDOM koku. Šo salīdzināšanas procesu sauc par "diffing".
- React izdomā minimālo izmaiņu kopumu, kas nepieciešams, lai pārveidotu veco VDOM par jauno.
- Šīs minimālās izmaiņas tiek apkopotas un piemērotas reālajam DOM vienā efektīvā operācijā.
Šis process, kas pazīstams kā saskaņošana, ir tas, kas padara React tik veiktspējīgu. Tā vietā, lai pārbūvētu visu māju, React rīkojas kā eksperts būvuzņēmējs, kurš precīzi identificē, kuri konkrēti ķieģeļi ir jānomaina, tādējādi samazinot darbu un traucējumus.
2. nodaļa: Problēma ar sarakstu renderēšanu bez atslēgām
Tagad apskatīsim, kur šī elegantā sistēma var saskarties ar grūtībām. Apsveriet vienkāršu komponenti, kas renderē lietotāju sarakstu:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li>{user.name}</li>
))}
</ul>
);
}
Kad šī komponente pirmo reizi tiek renderēta, React izveido VDOM koku. Ja mēs pievienojam jaunu lietotāju `users` masīva *beigās*, React "diffing" algoritms to apstrādā veiksmīgi. Tas salīdzina veco un jauno sarakstu, redz jaunu elementu beigās un vienkārši pievieno jaunu `<li>` reālajam DOM. Efektīvi un vienkārši.
Bet kas notiek, ja mēs pievienojam jaunu lietotāju saraksta sākumā vai pārkārtojam elementus?
Pieņemsim, ka mūsu sākotnējais saraksts ir:
- Alise
- Bobs
Un pēc atjaunināšanas tas kļūst par:
- Čārlijs
- Alise
- Bobs
Bez unikāliem identifikatoriem React salīdzina abus sarakstus, pamatojoties uz to secību (indeksu). Lūk, ko tas redz:
- Pozīcija 0: Vecais elements bija "Alise". Jaunais elements ir "Čārlijs". React secina, ka komponente šajā pozīcijā ir jāatjaunina. Tas mutē esošo DOM mezglu, mainot tā saturu no "Alise" uz "Čārlijs".
- Pozīcija 1: Vecais elements bija "Bobs". Jaunais elements ir "Alise". React mutē otro DOM mezglu, mainot tā saturu no "Bobs" uz "Alise".
- Pozīcija 2: Šeit iepriekš nebija elementa. Jaunais elements ir "Bobs". React izveido un ievieto jaunu DOM mezglu priekš "Bobs".
Tas ir neticami neefektīvi. Tā vietā, lai sākumā ievietotu tikai vienu jaunu elementu "Čārlijs", React veica divas mutācijas un vienu ievietošanu. Lielam sarakstam vai saraksta elementiem, kas ir sarežģītas komponentes ar savu stāvokli, šis nevajadzīgais darbs noved pie ievērojamas veiktspējas pasliktināšanās un, kas ir vēl svarīgāk, pie potenciālām kļūdām komponentes stāvoklī.
Tāpēc, ja palaidīsiet iepriekš minēto kodu, jūsu pārlūkprogrammas izstrādātāja konsolē parādīsies brīdinājums: "Warning: Each child in a list should have a unique 'key' prop." React jums skaidri norāda, ka tam nepieciešama palīdzība, lai efektīvi veiktu savu darbu.
3. nodaļa: `key` rekvizīts nāk palīgā
key
rekvizīts ir mājīens, kas nepieciešams React. Tas ir īpašs virknes atribūts, ko jūs nodrošināt, veidojot elementu sarakstus. Atslēgas piešķir katram elementam stabilu un unikālu identitāti starp renderēšanas reizēm.
Pārrakstīsim mūsu `UserList` komponenti ar atslēgām:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Šeit mēs pieņemam, ka katram `user` objektam ir unikāls `id` īpašums (piemēram, no datu bāzes). Tagad atgriezīsimies pie mūsu scenārija.
Sākotnējie dati:
[{ id: 'u1', name: 'Alice' }, { id: 'u2', name: 'Bob' }]
Atjauninātie dati:
[{ id: 'u3', name: 'Charlie' }, { id: 'u1', name: 'Alice' }, { id: 'u2', name: 'Bob' }]
Ar atslēgām React "diffing" process ir daudz gudrāks:
- React aplūko jaunā VDOM `<ul>` bērnelementus un pārbauda to atslēgas. Tas redz `u3`, `u1` un `u2`.
- Tad tas pārbauda iepriekšējā VDOM bērnelementus un to atslēgas. Tas redz `u1` un `u2`.
- React zina, ka komponentes ar atslēgām `u1` un `u2` jau pastāv. Tam nav nepieciešams tās mutēt; tam vienkārši jāpārvieto to atbilstošie DOM mezgli uz jaunajām pozīcijām.
- React redz, ka atslēga `u3` ir jauna. Tas izveido jaunu komponenti un DOM mezglu priekš "Čārlijs" un ievieto to sākumā.
Rezultāts ir viena DOM ievietošana un neliela pārkārtošana, kas ir daudz efektīvāk nekā vairākas mutācijas un ievietošana, ko redzējām iepriekš. Atslēgas nodrošina stabilu identitāti, ļaujot React izsekot elementus starp renderēšanas reizēm, neatkarīgi no to pozīcijas masīvā.
4. nodaļa: Pareizās atslēgas izvēle - Zelta likumi
key
rekvizīta efektivitāte ir pilnībā atkarīga no pareizās vērtības izvēles. Ir skaidras labākās prakses un bīstami antipaterni, no kuriem jāuzmanās.
Labākā atslēga: Unikāli un stabili ID
Ideāla atslēga ir vērtība, kas unikāli un pastāvīgi identificē elementu sarakstā. Gandrīz vienmēr tas ir unikāls ID no jūsu datu avota.
- Tai jābūt unikālai starp blakuselementiem (siblings). Atslēgām nav jābūt globāli unikālām, tikai unikālām elementu sarakstā, kas tiek renderēts tajā līmenī. Diviem dažādiem sarakstiem vienā lapā var būt elementi ar vienādām atslēgām.
- Tai jābūt stabilai. Konkrēta datu elementa atslēgai nevajadzētu mainīties starp renderēšanas reizēm. Ja jūs atkārtoti ielādējat datus par Alisi, viņai joprojām vajadzētu būt tam pašam `id`.
Lieliski atslēgu avoti ietver:
- Datu bāzes primārās atslēgas (piem., `user.id`, `product.sku`)
- Universāli unikālie identifikatori (UUID)
- Unikāla, nemainīga virkne no jūsu datiem (piem., grāmatas ISBN)
// LABI: Tiek izmantots stabils, unikāls ID no datiem.
<div>
{products.map(product => (
<ProductItem key={product.sku} product={product} />
))}
</div>
Antipaterns: Masīva indeksa izmantošana kā atslēga
Bieža kļūda ir izmantot masīva indeksu kā atslēgu:
// SLIKTI: Masīva indeksa izmantošana kā atslēga.
<div>
{items.map((item, index) => (
<ListItem key={index} item={item} />
))}
</div>
Lai gan tas apklusinās React brīdinājumu, tas var radīt nopietnas problēmas un parasti tiek uzskatīts par antipaternu. Indeksa izmantošana kā atslēga norāda React, ka elementa identitāte ir saistīta ar tā pozīciju sarakstā. Tā ir būtībā tā pati problēma, kāda rodas, ja nav atslēgas vispār, kad sarakstu var pārkārtot, filtrēt vai tam pievienot/noņemt elementus no sākuma vai vidus.
Stāvokļa pārvaldības kļūda:
Visbīstamākais indeksa atslēgu izmantošanas blakusefekts parādās, kad jūsu saraksta elementi pārvalda savu stāvokli. Iedomājieties ievades lauku sarakstu:
function UnstableList() {
const [items, setItems] = React.useState([{ id: 1, text: 'First' }, { id: 2, text: 'Second' }]);
const handleAddItemToTop = () => {
setItems([{ id: 3, text: 'New Top' }, ...items]);
};
return (
<div>
<button onClick={handleAddItemToTop}>Add to Top</button>
{items.map((item, index) => (
<div key={index}>
<label>{item.text}: </label>
<input type="text" />
</div>
))}
</div>
);
}
Izmēģiniet šo domu eksperimentu:
- Saraksts tiek renderēts ar "Pirmais" un "Otrais".
- Jūs ierakstāt "Sveiki" pirmajā ievades laukā (tas, kas paredzēts "Pirmais").
- Jūs noklikšķināt uz pogas "Pievienot augšā".
Ko jūs sagaidāt, ka notiks? Jūs sagaidītu, ka parādīsies jauns, tukšs ievades lauks priekš "Jauns augšā", un ievades lauks priekš "Pirmais" (kurā joprojām ir "Sveiki") pārvietosies uz leju. Kas patiesībā notiek? Ievades lauks pirmajā pozīcijā (indekss 0), kurā joprojām ir "Sveiki", paliek. Bet tagad tas ir saistīts ar jauno datu elementu "Jauns augšā". Ievades komponentes stāvoklis (tās iekšējā vērtība) ir piesaistīts tās pozīcijai (key=0), nevis datiem, kurus tai vajadzētu attēlot. Tā ir klasiska un mulsinoša kļūda, ko izraisa indeksa atslēgas.
Ja jūs vienkārši nomaināt `key={index}` uz `key={item.id}`, problēma tiek atrisināta. React tagad pareizi saistīs komponentes stāvokli ar stabilu datu ID.
Kad ir pieņemami izmantot indeksa atslēgu?
Ir reti gadījumi, kad indeksa izmantošana ir droša, bet jums jāatbilst visiem šiem nosacījumiem:
- Saraksts ir statisks: tas nekad netiks pārkārtots, filtrēts, vai tam netiks pievienoti/noņemti elementi no jebkuras vietas, izņemot beigas.
- Saraksta elementiem nav stabilu ID.
- Katrai vienībai renderētās komponentes ir vienkāršas un tām nav iekšēja stāvokļa.
Pat tad bieži vien ir labāk, ja iespējams, ģenerēt pagaidu, bet stabilu ID. Indeksa izmantošanai vienmēr jābūt apzinātai izvēlei, nevis noklusējuma rīcībai.
Sliktākais variants: `Math.random()`
Nekad, nekad neizmantojiet `Math.random()` vai jebkuru citu nedeterminētu vērtību kā atslēgu:
// BRIESMĪGI: Nedariet to!
<div>
{items.map(item => (
<ListItem key={Math.random()} item={item} />
))}
</div>
Atslēga, kas ģenerēta ar `Math.random()`, garantēti būs atšķirīga katrā renderēšanas reizē. Tas norāda React, ka viss iepriekšējā renderējuma komponenšu saraksts ir iznīcināts un ir izveidots pilnīgi jauns, atšķirīgu komponenšu saraksts. Tas liek React atvienot (unmount) visas vecās komponentes (iznīcinot to stāvokli) un pievienot (mount) visas jaunās. Tas pilnībā sagrauj saskaņošanas mērķi un ir sliktākais iespējamais variants veiktspējai.
5. nodaļa: Papildu koncepcijas un biežāk uzdotie jautājumi
Atslēgas un `React.Fragment`
Dažreiz no `map` atzvanīšanas funkcijas ir jāatgriež vairāki elementi. Standarta veids, kā to izdarīt, ir ar `React.Fragment`. Kad jūs to darāt, `key` ir jānovieto uz pašas `Fragment` komponentes.
function Glossary({ terms }) {
return (
<dl>
{terms.map(term => (
// Atslēga tiek likta uz Fragment, nevis uz bērnelementiem.
<React.Fragment key={term.id}>
<dt>{term.name}</dt>
<dd>{term.definition}</dd>
</React.Fragment>
))}
</dl>
);
}
Svarīgi: Saīsinātā sintakse `<>...</>` neatbalsta atslēgas. Ja jūsu sarakstam nepieciešami fragmenti, jums jāizmanto skaidrā `<React.Fragment>` sintakse.
Atslēgām jābūt unikālām tikai starp blakuselementiem
Bieži sastopams nepareizs uzskats ir, ka atslēgām jābūt globāli unikālām visā jūsu lietojumprogrammā. Tā nav taisnība. Atslēgai jābūt unikālai tikai tās tiešajā blakuselementu sarakstā.
function CourseRoster({ courses }) {
return (
<div>
{courses.map(course => (
<div key={course.id}> {/* Atslēga kursam */}
<h3>{course.title}</h3>
<ul>
{course.students.map(student => (
// Šai studenta atslēgai jābūt unikālai tikai šī konkrētā kursa studentu sarakstā.
<li key={student.id}>{student.name}</li>
))}
</ul>
</div>
))}
</div>
);
}
Iepriekš minētajā piemērā divos dažādos kursos varētu būt students ar `id: 's1'`. Tas ir pilnīgi pieņemami, jo atslēgas tiek novērtētas dažādos vecākelementos `<ul>`.
Atslēgu izmantošana, lai apzināti atiestatītu komponentes stāvokli
Lai gan atslēgas galvenokārt ir paredzētas sarakstu optimizācijai, tām ir dziļāks mērķis: tās definē komponentes identitāti. Ja komponentes atslēga mainās, React nemēģinās atjaunināt esošo komponenti. Tā vietā tas iznīcinās veco komponenti (un visus tās bērnelementus) un izveidos pilnīgi jaunu no nulles. Tas atvieno veco instanci un pievieno jaunu, efektīvi atiestatot tās stāvokli.
Tas var būt spēcīgs un deklaratīvs veids, kā atiestatīt komponenti. Piemēram, iedomājieties `UserProfile` komponenti, kas ielādē datus, pamatojoties uz `userId`.
function App() {
const [userId, setUserId] = React.useState('user-1');
return (
<div>
<button onClick={() => setUserId('user-1')}>View User 1</button>
<button onClick={() => setUserId('user-2')}>View User 2</button>
<UserProfile key={userId} id={userId} />
</div>
);
}
Novietojot `key={userId}` uz `UserProfile` komponentes, mēs garantējam, ka ikreiz, kad `userId` mainās, visa `UserProfile` komponente tiks izmesta un tiks izveidota jauna. Tas novērš potenciālas kļūdas, kurās varētu palikt stāvoklis no iepriekšējā lietotāja profila (piemēram, formas dati vai ielādēts saturs). Tas ir tīrs un skaidrs veids, kā pārvaldīt komponentes identitāti un dzīves ciklu.
Noslēgums: Labāka React koda rakstīšana
`key` rekvizīts ir daudz vairāk nekā tikai veids, kā apklusināt konsoles brīdinājumu. Tā ir fundamentāla instrukcija React, kas sniedz kritisko informāciju, kas nepieciešama tā saskaņošanas algoritmam, lai tas darbotos efektīvi un pareizi. Atslēgu lietošanas apgūšana ir profesionāla React izstrādātāja pazīme.
Apkoposim galvenos secinājumus:
- Atslēgas ir būtiskas veiktspējai: Tās ļauj React "diffing" algoritmam efektīvi pievienot, noņemt un pārkārtot elementus sarakstā bez nevajadzīgām DOM mutācijām.
- Vienmēr izmantojiet stabilus un unikālus ID: Labākā atslēga ir unikāls identifikators no jūsu datiem, kas nemainās starp renderēšanas reizēm.
- Izvairieties no masīva indeksiem kā atslēgām: Elementa indeksa izmantošana kā atslēga var novest pie sliktas veiktspējas un smalkām, kaitinošām stāvokļa pārvaldības kļūdām, īpaši dinamiskos sarakstos.
- Nekad neizmantojiet nejaušas vai nestabilas atslēgas: Tas ir sliktākais scenārijs, jo tas liek React pārradīt visu komponenšu sarakstu katrā renderēšanas reizē, iznīcinot veiktspēju un stāvokli.
- Atslēgas definē komponentes identitāti: Jūs varat izmantot šo uzvedību, lai apzināti atiestatītu komponentes stāvokli, mainot tās atslēgu.
Iekšēji apgūstot šos principus, jūs ne tikai rakstīsiet ātrākas, uzticamākas React lietojumprogrammas, bet arī iegūsiet dziļāku izpratni par bibliotēkas pamatmehānismiem. Nākamreiz, kad veidosiet sarakstu, izmantojot masīva `map` metodi, pievērsiet `key` rekvizītam pelnīto uzmanību. Jūsu lietojumprogrammas veiktspēja — un jūsu nākotnes "es" — jums par to pateiksies.