Išsamus vadovas, kaip optimizuoti „React“ programas, išvengiant nereikalingų pervaizdavimų. Išmokite memoizacijos, „PureComponent“, „shouldComponentUpdate“ ir kitų technikų geresniam našumui.
„React“ atvaizdavimo optimizavimas: įvaldykite nereikalingų pervaizdavimų prevenciją
„React“, galinga „JavaScript“ biblioteka, skirta vartotojo sąsajoms kurti, kartais gali susidurti su našumo problemomis dėl perteklinio ar nereikalingo pervaizdavimo. Sudėtingose programose su daugybe komponentų šie pervaizdavimai gali žymiai pabloginti našumą ir lemti lėtą vartotojo patirtį. Šis vadovas pateikia išsamią apžvalgą technikų, kaip išvengti nereikalingų pervaizdavimų „React“ programose, užtikrinant, kad jūsų programos būtų greitos, efektyvios ir reaguojančios vartotojams visame pasaulyje.
„React“ pervaizdavimų supratimas
Prieš pradedant nagrinėti optimizavimo technikas, svarbu suprasti, kaip veikia „React“ atvaizdavimo procesas. Kai komponento būsena (state) ar savybės (props) pasikeičia, „React“ sukelia to komponento ir jo vaikinių komponentų pervaizdavimą. Šis procesas apima virtualaus DOM atnaujinimą ir jo palyginimą su ankstesne versija, siekiant nustatyti minimalų pakeitimų rinkinį, kurį reikia pritaikyti tikram DOM.
Tačiau ne visi būsenos ar savybių pasikeitimai reikalauja DOM atnaujinimo. Jei naujas virtualus DOM yra identiškas ankstesniam, pervaizdavimas iš esmės yra resursų švaistymas. Šie nereikalingi pervaizdavimai naudoja vertingus CPU ciklus ir gali sukelti našumo problemų, ypač programose su sudėtingais komponentų medžiais.
Nereikalingų pervaizdavimų nustatymas
Pirmasis žingsnis optimizuojant pervaizdavimus yra nustatyti, kur jie vyksta. „React“ siūlo keletą įrankių, kurie jums padės tai padaryti:
1. „React Profiler“
„React Profiler“, pasiekiamas „React DevTools“ plėtinyje „Chrome“ ir „Firefox“ naršyklėms, leidžia įrašyti ir analizuoti jūsų „React“ komponentų našumą. Jis suteikia įžvalgų apie tai, kurie komponentai yra pervaizduojami, kiek laiko trunka jų atvaizdavimas ir kodėl jie yra pervaizduojami.
Norėdami naudoti „Profiler“, tiesiog įjunkite mygtuką „Record“ „DevTools“ įrankiuose ir sąveikaukite su savo programa. Po įrašymo „Profiler“ parodys liepsnos diagramą (flame chart), vaizduojančią komponentų medį ir jo atvaizdavimo laikus. Komponentai, kurie ilgai atvaizduojami arba dažnai pervaizduojami, yra pagrindiniai kandidatai optimizavimui.
2. „Why Did You Render?“
„Why Did You Render?“ yra biblioteka, kuri pataiso „React“, kad praneštų jums apie potencialiai nereikalingus pervaizdavimus, išvesdama į konsolę informaciją apie konkrečias savybes, kurios sukėlė pervaizdavimą. Tai gali būti itin naudinga nustatant pagrindinę pervaizdavimo problemų priežastį.
Norėdami naudoti „Why Did You Render?“, įdiekite ją kaip kūrimo priklausomybę:
npm install @welldone-software/why-did-you-render --save-dev
Tada importuokite ją į savo programos įvesties tašką (pvz., index.js):
import whyDidYouRender from '@welldone-software/why-did-you-render';
if (process.env.NODE_ENV === 'development') {
whyDidYouRender(React, {
include: [/.*/]
});
}
Šis kodas įjungs „Why Did You Render?“ kūrimo režimu ir išves į konsolę informaciją apie potencialiai nereikalingus pervaizdavimus.
3. „Console.log“ teiginiai
Paprasta, bet veiksminga technika yra pridėti console.log
teiginius savo komponento render
metode (arba funkcinio komponento kūne), kad galėtumėte sekti, kada jis pervaizduojamas. Nors tai mažiau sudėtinga nei „Profiler“ ar „Why Did You Render?“, tai gali greitai išryškinti komponentus, kurie pervaizduojami dažniau nei tikėtasi.
Technikos, kaip išvengti nereikalingų pervaizdavimų
Kai nustatysite komponentus, kurie sukelia našumo problemų, galite panaudoti įvairias technikas, kad išvengtumėte nereikalingų pervaizdavimų:
1. Memoizacija (Memoization)
Memoizacija yra galinga optimizavimo technika, kuri apima brangių funkcijų iškvietimų rezultatų kaupimą talpykloje (caching) ir grąžinimą iš talpyklos, kai vėl gaunamos tos pačios įvesties reikšmės. „React“ aplinkoje memoizacija gali būti naudojama siekiant išvengti komponentų pervaizdavimo, jei jų savybės (props) nepasikeitė.
a. React.memo
React.memo
yra aukštesnės eilės komponentas (higher-order component), kuris memoizuoja funkcinį komponentą. Jis atlieka paviršutinišką (shallow) esamų savybių palyginimą su ankstesnėmis savybėmis ir pervaizduoja komponentą tik tuo atveju, jei savybės pasikeitė.
Pavyzdys:
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.data}</div>;
});
Pagal numatytuosius nustatymus React.memo
atlieka paviršutinišką visų savybių palyginimą. Galite pateikti pasirinktinę palyginimo funkciją kaip antrąjį argumentą React.memo
, kad pritaikytumėte palyginimo logiką.
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.data}</div>;
}, (prevProps, nextProps) => {
// Grąžinkite true, jei savybės yra lygios, false, jei savybės skiriasi
return prevProps.data === nextProps.data;
});
b. useMemo
useMemo
yra „React“ „kabliukas“ (hook), kuris memoizuoja skaičiavimo rezultatą. Jis priima funkciją ir priklausomybių masyvą kaip argumentus. Funkcija yra iš naujo vykdoma tik tada, kai pasikeičia viena iš priklausomybių, o memoizuotas rezultatas grąžinamas vėlesniuose atvaizdavimuose.
useMemo
yra ypač naudingas memoizuojant brangius skaičiavimus arba kuriant stabilias nuorodas į objektus ar funkcijas, kurios perduodamos kaip savybės vaikiniams komponentams.
Pavyzdys:
const memoizedValue = useMemo(() => {
// Čia atlikite brangų skaičiavimą
return computeExpensiveValue(a, b);
}, [a, b]);
2. „PureComponent“
PureComponent
yra bazinė klasė „React“ komponentams, kuri savo shouldComponentUpdate
metode įgyvendina paviršutinišką savybių (props) ir būsenos (state) palyginimą. Jei savybės ir būsena nepasikeitė, komponentas nebus pervaizduotas.
PureComponent
yra geras pasirinkimas komponentams, kurie atvaizdavimui priklauso tik nuo savo savybių ir būsenos ir nesiremia kontekstu ar kitais išoriniais veiksniais.
Pavyzdys:
class MyComponent extends React.PureComponent {
render() {
return <div>{this.props.data}</div>;
}
}
Svarbi pastaba: PureComponent
ir React.memo
atlieka paviršutiniškus palyginimus. Tai reiškia, kad jie lygina tik objektų ir masyvų nuorodas, o ne jų turinį. Jei jūsų savybės ar būsena turi įdėtų objektų ar masyvų, gali tekti naudoti tokias technikas kaip nekintamumas (immutability), kad užtikrintumėte, jog pakeitimai būtų teisingai aptikti.
3. „shouldComponentUpdate“
shouldComponentUpdate
gyvavimo ciklo metodas leidžia rankiniu būdu valdyti, ar komponentas turėtų būti pervaizduotas. Šis metodas gauna kitas savybes (nextProps) ir kitą būseną (nextState) kaip argumentus ir turėtų grąžinti true
, jei komponentas turėtų būti pervaizduotas, arba false
, jei ne.
Nors shouldComponentUpdate
suteikia didžiausią kontrolę pervaizdavimui, jis taip pat reikalauja daugiausiai rankinio darbo. Turite atidžiai palyginti atitinkamas savybes ir būseną, kad nustatytumėte, ar pervaizdavimas yra būtinas.
Pavyzdys:
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// Čia palyginkite savybes ir būseną
return nextProps.data !== this.props.data || nextState.count !== this.state.count;
}
render() {
return <div>{this.props.data}</div>;
}
}
Atsargiai: Neteisingai įgyvendintas shouldComponentUpdate
gali sukelti netikėtą elgesį ir klaidas. Įsitikinkite, kad jūsų palyginimo logika yra išsami ir atsižvelgia į visus svarbius veiksnius.
4. „useCallback“
useCallback
yra „React“ „kabliukas“ (hook), kuris memoizuoja funkcijos apibrėžimą. Jis priima funkciją ir priklausomybių masyvą kaip argumentus. Funkcija yra iš naujo apibrėžiama tik tada, kai pasikeičia viena iš priklausomybių, o memoizuota funkcija grąžinama vėlesniuose atvaizdavimuose.
useCallback
yra ypač naudingas perduodant funkcijas kaip savybes vaikiniams komponentams, kurie naudoja React.memo
arba PureComponent
. Memoizuodami funkciją, galite išvengti nereikalingo vaikinio komponento pervaizdavimo, kai tėvinis komponentas pervaizduojamas.
Pavyzdys:
const handleClick = useCallback(() => {
// Apdorokite paspaudimo įvykį
console.log('Clicked!');
}, []);
5. Nekintamumas (Immutability)
Nekintamumas yra programavimo koncepcija, kuri apima duomenų traktavimą kaip nekintamus, o tai reiškia, kad jų negalima pakeisti po sukūrimo. Dirbant su nekintamais duomenimis, bet kokie pakeitimai sukuria naują duomenų struktūrą, o ne modifikuoja esamą.
Nekintamumas yra labai svarbus optimizuojant „React“ pervaizdavimus, nes jis leidžia „React“ lengvai aptikti savybių ir būsenos pakeitimus naudojant paviršutiniškus palyginimus. Jei modifikuojate objektą ar masyvą tiesiogiai, „React“ negalės aptikti pakeitimo, nes nuoroda į objektą ar masyvą išlieka ta pati.
Galite naudoti tokias bibliotekas kaip „Immutable.js“ ar „Immer“, kad dirbtumėte su nekintamais duomenimis „React“ programose. Šios bibliotekos suteikia duomenų struktūras ir funkcijas, kurios palengvina nekintamų duomenų kūrimą ir manipuliavimą.
Pavyzdys naudojant „Immer“:
import { useImmer } from 'use-immer';
function MyComponent() {
const [data, setData] = useImmer({
name: 'John',
age: 30
});
const updateName = () => {
setData(draft => {
draft.name = 'Jane';
});
};
return (
<div>
<p>Name: {data.name}</p>
<button onClick={updateName}>Update Name</button>
</div>
);
}
6. Kodo padalijimas (Code Splitting) ir tingusis įkėlimas (Lazy Loading)
Kodo padalijimas yra technika, kuri apima jūsų programos kodo padalijimą į mažesnes dalis, kurias galima įkelti pagal poreikį. Tai gali žymiai pagerinti pradinį jūsų programos įkėlimo laiką, nes naršyklė turi atsisiųsti tik tą kodą, kuris yra būtinas dabartiniam vaizdui.
„React“ teikia integruotą palaikymą kodo padalijimui naudojant React.lazy
funkciją ir Suspense
komponentą. React.lazy
leidžia dinamiškai importuoti komponentus, o Suspense
leidžia rodyti atsarginę vartotojo sąsają, kol komponentas yra įkeliamas.
Pavyzdys:
import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
}
7. Efektyvus raktų (Keys) naudojimas
Atvaizduojant elementų sąrašus „React“ programose, labai svarbu kiekvienam elementui suteikti unikalų raktą. Raktai padeda „React“ nustatyti, kurie elementai pasikeitė, buvo pridėti ar pašalinti, leidžiant efektyviai atnaujinti DOM.
Venkite naudoti masyvo indeksus kaip raktus, nes jie gali pasikeisti, kai keičiasi elementų tvarka masyve, o tai sukelia nereikalingus pervaizdavimus. Vietoj to, naudokite unikalų identifikatorių kiekvienam elementui, pavyzdžiui, ID iš duomenų bazės arba sugeneruotą UUID.
8. Konteksto (Context) naudojimo optimizavimas
„React“ kontekstas suteikia būdą dalytis duomenimis tarp komponentų, aiškiai neperduodant savybių per kiekvieną komponentų medžio lygį. Tačiau perteklinis konteksto naudojimas gali sukelti našumo problemų, nes bet kuris komponentas, kuris naudoja kontekstą, bus pervaizduojamas, kai pasikeis konteksto vertė.
Norėdami optimizuoti konteksto naudojimą, apsvarstykite šias strategijas:
- Naudokite kelis, mažesnius kontekstus: Užuot naudoję vieną didelį kontekstą visiems programos duomenims saugoti, padalinkite jį į mažesnius, labiau sufokusuotus kontekstus. Tai sumažins komponentų, kurie pervaizduojami, kai pasikeičia konkreti konteksto vertė, skaičių.
- Memoizuokite konteksto vertes: Naudokite
useMemo
, kad memoizuotumėte vertes, kurias teikia konteksto teikėjas. Tai padės išvengti nereikalingų konteksto vartotojų pervaizdavimų, jei vertės iš tikrųjų nepasikeitė. - Apsvarstykite alternatyvas kontekstui: Kai kuriais atvejais kiti būsenos valdymo sprendimai, tokie kaip „Redux“ ar „Zustand“, gali būti tinkamesni nei kontekstas, ypač sudėtingoms programoms su dideliu komponentų skaičiumi ir dažnais būsenos atnaujinimais.
Tarptautiniai aspektai
Optimizuojant „React“ programas pasaulinei auditorijai, svarbu atsižvelgti į šiuos veiksnius:
- Skirtingas tinklo greitis: Vartotojai skirtinguose regionuose gali turėti labai skirtingą tinklo greitį. Optimizuokite savo programą, kad sumažintumėte duomenų, kuriuos reikia atsisiųsti ir perduoti per tinklą, kiekį. Apsvarstykite galimybę naudoti tokias technikas kaip vaizdų optimizavimas, kodo padalijimas ir tingusis įkėlimas.
- Įrenginių galimybės: Vartotojai gali naudotis jūsų programa įvairiais įrenginiais, nuo aukščiausios klasės išmaniųjų telefonų iki senesnių, mažiau galingų įrenginių. Optimizuokite savo programą, kad ji gerai veiktų įvairiuose įrenginiuose. Apsvarstykite galimybę naudoti tokias technikas kaip prisitaikantis dizainas (responsive design), adaptyvūs vaizdai ir našumo profiliavimas.
- Lokalizacija: Jei jūsų programa yra lokalizuota kelioms kalboms, įsitikinkite, kad lokalizacijos procesas nesukuria našumo problemų. Naudokite efektyvias lokalizacijos bibliotekas ir venkite tiesioginio teksto eilučių kodavimo savo komponentuose.
Pavyzdžiai iš realaus pasaulio
Panagrinėkime kelis realaus pasaulio pavyzdžius, kaip šios optimizavimo technikos gali būti pritaikytos:
1. E. prekybos produktų sąrašas
Įsivaizduokite e. prekybos svetainę su produktų sąrašo puslapiu, kuriame rodoma šimtai produktų. Kiekvienas produkto elementas yra atvaizduojamas kaip atskiras komponentas.
Be optimizavimo, kiekvieną kartą, kai vartotojas filtruoja ar rūšiuoja produktų sąrašą, visi produktų komponentai būtų pervaizduojami, o tai sukeltų lėtą ir stringančią patirtį. Norėdami tai optimizuoti, galėtumėte naudoti React.memo
, kad memoizuotumėte produktų komponentus, užtikrindami, kad jie būtų pervaizduojami tik tada, kai pasikeičia jų savybės (pvz., produkto pavadinimas, kaina, vaizdas).
2. Socialinių tinklų srautas
Socialinių tinklų srautas paprastai rodo įrašų sąrašą, kiekvieną su komentarais, „patinka“ paspaudimais ir kitais interaktyviais elementais. Viso srauto pervaizdavimas kiekvieną kartą, kai vartotojas paspaudžia „patinka“ ant įrašo ar prideda komentarą, būtų neefektyvus.
Norėdami tai optimizuoti, galėtumėte naudoti useCallback
, kad memoizuotumėte įvykių apdorojimo funkcijas, skirtas „patinka“ paspaudimams ir komentarams. Tai neleistų įrašų komponentams nereikalingai pervaizduoti, kai šios įvykių apdorojimo funkcijos yra suaktyvinamos.
3. Duomenų vizualizacijos prietaisų skydelis
Duomenų vizualizacijos prietaisų skydelis dažnai rodo sudėtingas diagramas ir grafikus, kurie dažnai atnaujinami naujais duomenimis. Šių diagramų pervaizdavimas kiekvieną kartą, kai keičiasi duomenys, gali būti skaičiavimo požiūriu brangus.
Norėdami tai optimizuoti, galėtumėte naudoti useMemo
, kad memoizuotumėte diagramų duomenis ir pervaizduotumėte diagramas tik tada, kai keičiasi memoizuoti duomenys. Tai žymiai sumažintų pervaizdavimų skaičių ir pagerintų bendrą prietaisų skydelio našumą.
Gerosios praktikos
Štai keletas gerųjų praktikų, kurias reikia turėti omenyje optimizuojant „React“ pervaizdavimus:
- Profiluokite savo programą: Naudokite „React Profiler“ arba „Why Did You Render?“, kad nustatytumėte komponentus, kurie sukelia našumo problemų.
- Pradėkite nuo lengviausiai pasiekiamų vaisių: Sutelkite dėmesį į tų komponentų optimizavimą, kurie pervaizduojami dažniausiai arba kurių atvaizdavimas trunka ilgiausiai.
- Naudokite memoizaciją apgalvotai: Nememoizuokite kiekvieno komponento, nes pati memoizacija turi savo kainą. Memoizuokite tik tuos komponentus, kurie iš tikrųjų sukelia našumo problemų.
- Naudokite nekintamumą: Naudokite nekintamas duomenų struktūras, kad „React“ būtų lengviau aptikti savybių ir būsenos pakeitimus.
- Išlaikykite komponentus mažus ir sufokusuotus: Mažesnius, labiau sufokusuotus komponentus lengviau optimizuoti ir prižiūrėti.
- Išbandykite savo optimizacijas: Pritaikę optimizavimo technikas, kruopščiai išbandykite savo programą, kad įsitikintumėte, jog optimizacijos turi norimą poveikį ir neįvedė jokių naujų klaidų.
Išvada
Nereikalingų pervaizdavimų prevencija yra labai svarbi optimizuojant „React“ programų našumą. Suprasdami, kaip veikia „React“ atvaizdavimo procesas, ir taikydami šiame vadove aprašytas technikas, galite žymiai pagerinti savo programų reagavimą ir efektyvumą, suteikdami geresnę vartotojo patirtį žmonėms visame pasaulyje. Nepamirškite profiliuoti savo programos, nustatyti komponentus, kurie sukelia našumo problemų, ir taikyti atitinkamas optimizavimo technikas šioms problemoms spręsti. Laikydamiesi šių gerųjų praktikų, galite užtikrinti, kad jūsų „React“ programos būtų greitos, efektyvios ir mastelio keitimui pritaikytos, nepriklausomai nuo jūsų kodo bazės sudėtingumo ar dydžio.