Põhjalik juhend Reacti rakenduste jõudluse optimeerimiseks, kasutades useMemo, useCallback ja React.memo. Õppige vältima tarbetuid uuesti renderdamisi ja parandama kasutajakogemust.
Reacti Jõudluse Optimeerimine: useMemo, useCallback ja React.memo meisterlik valdamine
React, populaarne JavaScripti teek kasutajaliideste loomiseks, on tuntud oma komponendipõhise arhitektuuri ja deklaratiivse stiili poolest. Rakenduste keerukuse kasvades võib aga jõudlus muutuda murekohaks. Komponentide tarbetu uuesti renderdamine võib põhjustada aeglast jõudlust ja halba kasutajakogemust. Õnneks pakub React mitmeid tööriistu jõudluse optimeerimiseks, sealhulgas useMemo
, useCallback
ja React.memo
. See juhend süveneb nendesse tehnikatesse, pakkudes praktilisi näiteid ja rakendatavaid teadmisi, mis aitavad teil luua suure jõudlusega Reacti rakendusi.
Reacti uuesti renderdamiste mõistmine
Enne optimeerimistehnikatesse süvenemist on oluline mõista, miks Reactis uuesti renderdamised toimuvad. Kui komponendi olek (state) või rekvisiidid (props) muutuvad, käivitab React selle komponendi ja potentsiaalselt ka selle alamkomponentide uuesti renderdamise. React kasutab virtuaalset DOM-i, et tegelikku DOM-i tõhusalt uuendada, kuid liigne uuesti renderdamine võib siiski jõudlust mõjutada, eriti keerukates rakendustes. Kujutage ette ülemaailmset e-kaubanduse platvormi, kus tootehinnad uuenevad sageli. Ilma optimeerimiseta võib isegi väike hinnamuutus käivitada uuesti renderdamised kogu tootenimekirjas, mõjutades kasutaja sirvimiskogemust.
Miks komponendid uuesti renderdatakse
- Oleku muutused: Kui komponendi olekut uuendatakse, kasutades
useState
võiuseReducer
, renderdab React komponendi uuesti. - Rekvisiitide muutused: Kui komponent saab oma vanemkomponendilt uusi rekvisiite, renderdatakse see uuesti.
- Vanemkomponendi uuesti renderdamine: Kui vanemkomponent uuesti renderdatakse, renderdatakse vaikimisi ka selle alamkomponendid uuesti, olenemata sellest, kas nende rekvisiidid on muutunud.
- Konteksti muutused: Komponendid, mis kasutavad Reacti konteksti, renderdatakse uuesti, kui konteksti väärtus muutub.
Jõudluse optimeerimise eesmärk on vältida tarbetuid uuesti renderdamisi, tagades, et komponendid uuenevad ainult siis, kui nende andmed on tegelikult muutunud. Mõelge stsenaariumile, mis hõlmab reaalajas andmete visualiseerimist aktsiaturu analüüsiks. Kui graafikukomponendid renderdatakse iga väikese andmeuuendusega tarbetult uuesti, muutub rakendus loiuks. Uuesti renderdamiste optimeerimine tagab sujuva ja reageeriva kasutajakogemuse.
Tutvustame useMemo: kulukate arvutuste memoiseerimine
useMemo
on Reacti hook, mis memoiseerib arvutuse tulemuse. Memoiseerimine on optimeerimistehnika, mis salvestab kulukate funktsioonikutsete tulemused ja taaskasutab neid tulemusi, kui samad sisendid uuesti esinevad. See väldib vajadust funktsiooni tarbetult uuesti käivitada.
Millal kasutada useMemo'd
- Kulukad arvutused: Kui komponent peab tegema arvutusmahuka arvutuse, mis põhineb selle rekvisiitidel või olekul.
- Viiteline võrdsus: Kui väärtus edastatakse rekvisiidina alamkomponendile, mis tugineb viitelisele võrdsusele, et otsustada, kas uuesti renderdada.
Kuidas useMemo töötab
useMemo
võtab kaks argumenti:
- Funktsioon, mis teostab arvutuse.
- Sõltuvuste massiiv.
Funktsioon käivitatakse ainult siis, kui üks massiivis olevatest sõltuvustest muutub. Vastasel juhul tagastab useMemo
eelnevalt memoiseeritud väärtuse.
Näide: Fibonacci jada arvutamine
Fibonacci jada on klassikaline näide arvutusmahukast arvutusest. Loome komponendi, mis arvutab n-inda Fibonacci arvu, kasutades useMemo
.
import React, { useState, useMemo } from 'react';
function Fibonacci({ n }) {
const fibonacciNumber = useMemo(() => {
console.log('Calculating Fibonacci...'); // Näitab, millal arvutus käivitub
function calculateFibonacci(num) {
if (num <= 1) {
return num;
}
return calculateFibonacci(num - 1) + calculateFibonacci(num - 2);
}
return calculateFibonacci(n);
}, [n]);
return Fibonacci({n}) = {fibonacciNumber}
;
}
function App() {
const [number, setNumber] = useState(5);
return (
setNumber(parseInt(e.target.value))}
/>
);
}
export default App;
Selles näites käivitatakse funktsioon calculateFibonacci
ainult siis, kui n
rekvisiit muutub. Ilma useMemo
'ta käivitataks funktsioon iga kord, kui Fibonacci
komponent uuesti renderdatakse, isegi kui n
jääks samaks. Kujutage ette, et see arvutus toimub ülemaailmsel finants-tööriistapaneelil – iga turu liikumine põhjustaks täieliku ümberarvutuse, mis tooks kaasa märkimisväärse viivituse. useMemo
hoiab selle ära.
Tutvustame useCallback: funktsioonide memoiseerimine
useCallback
on teine Reacti hook, mis memoiseerib funktsioone. See väldib uue funktsiooni eksemplari loomist igal renderdamisel, mis on eriti kasulik, kui tagasikutseid (callback) edastatakse rekvisiitidena alamkomponentidele.
Millal kasutada useCallback'i
- Tagasikutsete edastamine rekvisiitidena: Kui funktsioon edastatakse rekvisiidina alamkomponendile, mis kasutab uuesti renderdamiste optimeerimiseks
React.memo
võishouldComponentUpdate
. - Sündmuste käsitlejad: Kui komponendis defineeritakse sündmuste käsitleja funktsioone, et vältida alamkomponentide tarbetut uuesti renderdamist.
Kuidas useCallback töötab
useCallback
võtab kaks argumenti:
- Memoiseeritav funktsioon.
- Sõltuvuste massiiv.
Funktsioon luuakse uuesti ainult siis, kui üks massiivis olevatest sõltuvustest muutub. Vastasel juhul tagastab useCallback
sama funktsiooni eksemplari.
Näide: nupuvajutuse käsitlemine
Loome komponendi nupuga, mis käivitab tagasikutse funktsiooni. Kasutame useCallback
'i tagasikutse funktsiooni memoiseerimiseks.
import React, { useState, useCallback } from 'react';
function Button({ onClick, children }) {
console.log('Button re-rendered'); // Näitab, millal nupp uuesti renderdatakse
return ;
}
const MemoizedButton = React.memo(Button);
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Button clicked');
setCount((prevCount) => prevCount + 1);
}, []); // Tühi sõltuvuste massiiv tähendab, et funktsioon luuakse ainult üks kord
return (
Count: {count}
Increment
);
}
export default App;
Selles näites luuakse funktsioon handleClick
ainult üks kord, kuna sõltuvuste massiiv on tühi. Kui App
komponent renderdatakse uuesti count
oleku muutuse tõttu, jääb handleClick
funktsioon samaks. Komponent MemoizedButton
, mis on mähitud React.memo
'sse, renderdatakse uuesti ainult siis, kui selle rekvisiidid muutuvad. Kuna onClick
rekvisiit (handleClick
) jääb samaks, ei renderdata Button
komponenti tarbetult uuesti. Kujutage ette interaktiivset kaardirakendust. Iga kord, kui kasutaja midagi teeb, võib see mõjutada kümneid nupukomponente. Ilma useCallback
'ita renderdataks need nupud tarbetult uuesti, luues aeglase kogemuse. useCallback
'i kasutamine tagab sujuvama interaktsiooni.
Tutvustame React.memo: komponentide memoiseerimine
React.memo
on kõrgema järgu komponent (HOC), mis memoiseerib funktsionaalse komponendi. See takistab komponendi uuesti renderdamist, kui selle rekvisiidid pole muutunud. See sarnaneb klassikomponentide puhul kasutatava PureComponent
'iga.
Millal kasutada React.memo't
- Puhtad komponendid: Kui komponendi väljund sõltub ainult selle rekvisiitidest ja sellel pole oma olekut.
- Kulukas renderdamine: Kui komponendi renderdamisprotsess on arvutusmahukas.
- Sagedased uuesti renderdamised: Kui komponenti renderdatakse sageli uuesti, kuigi selle rekvisiidid pole muutunud.
Kuidas React.memo töötab
React.memo
mähiseb funktsionaalse komponendi ja võrdleb pindmiselt eelmisi ja järgmisi rekvisiite. Kui rekvisiidid on samad, siis komponenti uuesti ei renderdata.
Näide: kasutajaprofiili kuvamine
Loome komponendi, mis kuvab kasutajaprofiili. Kasutame React.memo
't, et vältida tarbetuid uuesti renderdamisi, kui kasutaja andmed pole muutunud.
import React from 'react';
function UserProfile({ user }) {
console.log('UserProfile re-rendered'); // Näitab, millal komponent uuesti renderdatakse
return (
Name: {user.name}
Email: {user.email}
);
}
const MemoizedUserProfile = React.memo(UserProfile, (prevProps, nextProps) => {
// Kohandatud võrdlusfunktsioon (valikuline)
return prevProps.user.id === nextProps.user.id; // Renderda uuesti ainult siis, kui kasutaja ID muutub
});
function App() {
const [user, setUser] = React.useState({
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
});
const updateUser = () => {
setUser({ ...user, name: 'Jane Doe' }); // Nime muutmine
};
return (
);
}
export default App;
Selles näites renderdatakse komponent MemoizedUserProfile
uuesti ainult siis, kui user.id
rekvisiit muutub. Isegi kui objekti user
muud omadused muutuvad (nt nimi või e-posti aadress), ei renderdata komponenti uuesti, kui ID ei ole erinev. See kohandatud võrdlusfunktsioon React.memo
sees võimaldab peenhäälestatud kontrolli selle üle, millal komponent uuesti renderdatakse. Mõelge sotsiaalmeedia platvormile, kus kasutajaprofiilid pidevalt uuenevad. Ilma React.memo
'ta põhjustaks kasutaja staatuse või profiilipildi muutmine profiilikomponendi täieliku uuesti renderdamise, isegi kui kasutaja põhiandmed jäävad samaks. React.memo
võimaldab sihipäraseid uuendusi ja parandab oluliselt jõudlust.
useMemo, useCallback ja React.memo kombineerimine
Need kolm tehnikat on kõige tõhusamad, kui neid koos kasutada. useMemo
memoiseerib kulukaid arvutusi, useCallback
memoiseerib funktsioone ja React.memo
memoiseerib komponente. Neid tehnikaid kombineerides saate oma Reacti rakenduses oluliselt vähendada tarbetute uuesti renderdamiste arvu.
Näide: keerukas komponent
Loome keerukama komponendi, mis demonstreerib, kuidas neid tehnikaid kombineerida.
import React, { useState, useCallback, useMemo } from 'react';
function ListItem({ item, onUpdate, onDelete }) {
console.log(`ListItem ${item.id} re-rendered`); // Näitab, millal komponent uuesti renderdatakse
return (
{item.text}
);
}
const MemoizedListItem = React.memo(ListItem);
function List({ items, onUpdate, onDelete }) {
console.log('List re-rendered'); // Näitab, millal komponent uuesti renderdatakse
return (
{items.map((item) => (
))}
);
}
const MemoizedList = React.memo(List);
function App() {
const [items, setItems] = useState([
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' },
{ id: 3, text: 'Item 3' },
]);
const handleUpdate = useCallback((id) => {
setItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, text: `Updated ${item.text}` } : item
)
);
}, []);
const handleDelete = useCallback((id) => {
setItems((prevItems) => prevItems.filter((item) => item.id !== id));
}, []);
const memoizedItems = useMemo(() => items, [items]);
return (
);
}
export default App;
Selles näites:
useCallback
'i kasutatakse funktsioonidehandleUpdate
jahandleDelete
memoiseerimiseks, vältides nende uuesti loomist igal renderdamisel.useMemo
'd kasutatakseitems
massiivi memoiseerimiseks, vältidesList
komponendi uuesti renderdamist, kui massiivi viide pole muutunud.React.memo
't kasutatakse komponentideListItem
jaList
memoiseerimiseks, vältides nende uuesti renderdamist, kui nende rekvisiidid pole muutunud.
See tehnikate kombinatsioon tagab, et komponendid renderdatakse uuesti ainult siis, kui see on vajalik, mis toob kaasa olulisi jõudluse paranemisi. Kujutage ette suuremahulist projektijuhtimise tööriista, kus ülesannete loendeid pidevalt uuendatakse, kustutatakse ja ümber järjestatakse. Ilma nende optimeerimisteta käivitaks iga väike muudatus ülesannete loendis uuesti renderdamiste kaskaadi, muutes rakenduse aeglaseks ja loiuks. Strateegiliselt kasutades useMemo
, useCallback
ja React.memo
, suudab rakendus jääda jõudlaks isegi keerukate andmete ja sagedaste uuenduste korral.
Täiendavad optimeerimistehnikad
Kuigi useMemo
, useCallback
ja React.memo
on võimsad tööriistad, ei ole need ainsad võimalused Reacti jõudluse optimeerimiseks. Siin on mõned täiendavad tehnikad, mida kaaluda:
- Koodi tükeldamine (Code Splitting): Jaotage oma rakendus väiksemateks osadeks, mida saab nõudmisel laadida. See vähendab esialgset laadimisaega ja parandab üldist jõudlust.
- Laadimine vajadusel (Lazy Loading): Laadige komponente ja ressursse ainult siis, kui neid on vaja. See võib olla eriti kasulik piltide ja muude suurte varade puhul.
- Virtualiseerimine: Renderdage ainult suure nimekirja või tabeli nähtav osa. See võib suurte andmehulkadega tegelemisel jõudlust oluliselt parandada. Selleks võivad abiks olla teegid nagu
react-window
jareact-virtualized
. - Debouncing ja Throttling: Piirake funktsioonide täitmise sagedust. See võib olla kasulik sündmuste, nagu kerimine ja akna suuruse muutmine, käsitlemisel.
- Muutmatus (Immutability): Kasutage muutumatuid andmestruktuure, et vältida juhuslikke mutatsioone ja lihtsustada muutuste tuvastamist.
Globaalsed kaalutlused optimeerimisel
Reacti rakenduste optimeerimisel globaalsele publikule on oluline arvestada selliste teguritega nagu võrgu latentsus, seadmete võimekus ja lokaliseerimine. Siin on mõned näpunäited:
- Sisuedastusvõrgud (CDN-id): Kasutage CDN-i, et serveerida staatilisi varasid kasutajatele lähematest asukohtadest. See vähendab võrgu latentsust ja parandab laadimisaegu.
- Piltide optimeerimine: Optimeerige pilte erinevate ekraanisuuruste ja eraldusvõimete jaoks. Kasutage failisuuruste vähendamiseks pakkimistehnikaid.
- Lokaliseerimine: Laadige iga kasutaja jaoks ainult vajalikud keeleressursid. See vähendab esialgset laadimisaega ja parandab kasutajakogemust.
- Adaptiivne laadimine: Tuvastage kasutaja võrguühendus ja seadme võimekus ning kohandage rakenduse käitumist vastavalt. Näiteks võite aeglase võrguühenduse või vanemate seadmetega kasutajate jaoks animatsioonid keelata või pildikvaliteeti vähendada.
Kokkuvõte
Reacti rakenduste jõudluse optimeerimine on sujuva ja reageeriva kasutajakogemuse pakkumiseks ülioluline. Valdades tehnikaid nagu useMemo
, useCallback
ja React.memo
ning arvestades globaalsete optimeerimisstrateegiatega, saate luua suure jõudlusega Reacti rakendusi, mis skaleeruvad vastavalt mitmekesise kasutajaskonna vajadustele. Ärge unustage oma rakendust profileerida, et tuvastada jõudluse kitsaskohad ja rakendada neid optimeerimistehnikaid strateegiliselt. Ärge optimeerige enneaegselt – keskenduge valdkondadele, kus saate saavutada kõige olulisema mõju.
See juhend pakub tugeva aluse Reacti jõudluse optimeerimiste mõistmiseks ja rakendamiseks. Reacti rakenduste arendamist jätkates pidage meeles, et peate seadma esikohale jõudluse ja otsima pidevalt uusi viise kasutajakogemuse parandamiseks.