Išsamus vadovas, kaip optimizuoti React programų našumą naudojant useMemo, useCallback ir React.memo. Sužinokite, kaip išvengti nereikalingų perpiešimų ir pagerinti vartotojo patirtį.
React našumo optimizavimas: useMemo, useCallback ir React.memo įvaldymas
React, populiari JavaScript biblioteka, skirta vartotojo sąsajoms kurti, yra žinoma dėl savo komponentų pagrindu sukurtos architektūros ir deklaratyvaus stiliaus. Tačiau, didėjant programų sudėtingumui, našumas gali tapti problema. Nereikalingi komponentų perpiešimai gali lemti lėtą našumą ir prastą vartotojo patirtį. Laimei, React suteikia keletą įrankių našumui optimizuoti, įskaitant useMemo
, useCallback
ir React.memo
. Šis vadovas gilinsis į šias technikas, pateikdamas praktinius pavyzdžius ir praktiškus patarimus, kurie padės jums kurti didelio našumo React programas.
React perpiešimų supratimas
Prieš gilindamiesi į optimizavimo metodus, svarbu suprasti, kodėl React vyksta perpiešimai. Kai pasikeičia komponento būsena arba props, React sukelia to komponento ir, potencialiai, jo vaikų komponentų perpiešimą. React naudoja virtualųjį DOM, kad efektyviai atnaujintų faktinį DOM, tačiau per didelis perpiešimas vis tiek gali turėti įtakos našumui, ypač sudėtingose programose. Įsivaizduokite pasaulinę e-komercijos platformą, kurioje dažnai atnaujinamos prekių kainos. Be optimizavimo, net nedidelis kainos pasikeitimas gali sukelti perpiešimus visame prekių sąraše, turėdamas įtakos vartotojo naršymui.
Kodėl komponentai perpiešiami
- Būsenos pakeitimai: Kai komponento būsena atnaujinama naudojant
useState
arbauseReducer
, React perpiešia komponentą. - Prop'ų pakeitimai: Jei komponentas gauna naujus prop'us iš savo tėvinio komponento, jis bus perpieštas.
- Tėvinio perpiešimai: Kai tėvinis komponentas perpiešiamas, jo vaiko komponentai taip pat bus perpiešiami pagal numatytuosius nustatymus, neatsižvelgiant į tai, ar pasikeitė jų prop'ai.
- Konteksto pakeitimai: Komponentai, kurie naudoja React Context, bus perpiešti, kai pasikeis konteksto reikšmė.
Našumo optimizavimo tikslas yra užkirsti kelią nereikalingiems perpiešimams, užtikrinant, kad komponentai atsinaujintų tik tada, kai iš tikrųjų pasikeitė jų duomenys. Apsvarstykite scenarijų, apimantį realaus laiko duomenų vizualizavimą akcijų rinkos analizei. Jei diagramos komponentai nereikalingai perpiešiami su kiekvienu nedideliu duomenų atnaujinimu, programa taps neatsakinga. Optimizuotas perpiešimas užtikrins sklandų ir reaguojantį vartotojo patyrimą.
useMemo pristatymas: brangių skaičiavimų memoizavimas
useMemo
yra React hook, kuris memoizuoja skaičiavimo rezultatą. Memoizavimas yra optimizavimo technika, kuri saugo brangių funkcijų iškvietimų rezultatus ir pakartotinai naudoja tuos rezultatus, kai vėl pasitaiko tie patys įėjimai. Tai neleidžia nereikalingai vėl vykdyti funkcijos.
Kada naudoti useMemo
- Brangūs skaičiavimai: Kai komponentas turi atlikti kompiuteriniu požiūriu intensyvų skaičiavimą, pagrįstą jo prop'ais arba būsena.
- Referencinis lygumas: Kai reikšmė perduodama kaip prop'as vaikui komponentui, kuris remiasi referenciniu lygumu, norėdamas nustatyti, ar perpiešti.
Kaip veikia useMemo
useMemo
priima du argumentus:
- Funkcija, kuri atlieka skaičiavimą.
- Priklausomybių masyvas.
Funkcija vykdoma tik tada, kai pasikeičia viena iš masyvo priklausomybių. Priešingu atveju, useMemo
grąžina anksčiau memoizuotą reikšmę.
Pavyzdys: Fibonačio sekos skaičiavimas
Fibonačio seka yra klasikinis kompiuteriniu požiūriu intensyvaus skaičiavimo pavyzdys. Sukurkime komponentą, kuris apskaičiuoja n-tąjį Fibonačio skaičių, naudodami useMemo
.
import React, { useState, useMemo } from 'react';
function Fibonacci({ n }) {
const fibonacciNumber = useMemo(() => {
console.log('Skaičiuojamas Fibonačio...'); // Parodo, kada vykdomas skaičiavimas
function calculateFibonacci(num) {
if (num <= 1) {
return num;
}
return calculateFibonacci(num - 1) + calculateFibonacci(num - 2);
}
return calculateFibonacci(n);
}, [n]);
return Fibonačio({n}) = {fibonacciNumber}
;
}
function App() {
const [number, setNumber] = useState(5);
return (
setNumber(parseInt(e.target.value))}
/>
);
}
export default App;
Šiame pavyzdyje funkcija calculateFibonacci
vykdoma tik tada, kai pasikeičia prop'as n
. Be useMemo
, funkcija būtų vykdoma su kiekvienu Fibonacci
komponento perpiešimu, net jei n
liktų tas pats. Įsivaizduokite šį skaičiavimą, vykstantį globaliame finansų informaciniame skydelyje – kiekvienas rinkos judėjimas sukelia visišką perskaičiavimą, o tai lemia didelį atsilikimą. useMemo
to neleidžia.
useCallback pristatymas: funkcijų memoizavimas
useCallback
yra dar vienas React hook, kuris memoizuoja funkcijas. Jis neleidžia sukurti naujo funkcijos egzemplioriaus su kiekvienu perpiešimu, o tai gali būti ypač naudinga, kai atgaliniai skambučiai perduodami kaip prop'ai vaikų komponentams.
Kada naudoti useCallback
- Atgalinių skambučių perdavimas kaip prop'us: Kai funkcija perduodama kaip prop'as vaikų komponentui, kuris naudoja
React.memo
arbashouldComponentUpdate
, kad optimizuotų perpiešimus. - Įvykių tvarkyklės: Kai komponente apibrėžiamos įvykių tvarkymo funkcijos, norint išvengti nereikalingų vaikų komponentų perpiešimų.
Kaip veikia useCallback
useCallback
priima du argumentus:
- Funkcija, kurią reikia memoizuoti.
- Priklausomybių masyvas.
Funkcija atkuriama tik tada, kai pasikeičia viena iš masyvo priklausomybių. Priešingu atveju, useCallback
grąžina tą patį funkcijos egzempliorių.
Pavyzdys: mygtuko paspaudimo tvarkymas
Sukursime komponentą su mygtuku, kuris suaktyvina atgalinio skambučio funkciją. Naudosime useCallback
, kad memoizuotume atgalinio skambučio funkciją.
import React, { useState, useCallback } from 'react';
function Button({ onClick, children }) {
console.log('Mygtukas perpieštas'); // Parodo, kada perpiešiamas mygtukas
return ;
}
const MemoizedButton = React.memo(Button);
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Mygtukas paspaustas');
setCount((prevCount) => prevCount + 1);
}, []); // Tuščias priklausomybių masyvas reiškia, kad funkcija sukurta tik vieną kartą
return (
Skaičius: {count}
Didinti
);
}
export default App;
Šiame pavyzdyje funkcija handleClick
sukuriama tik vieną kartą, nes priklausomybių masyvas yra tuščias. Kai App
komponentas perpiešiamas dėl count
būsenos pasikeitimo, funkcija handleClick
lieka ta pati. MemoizedButton
komponentas, apvyniotas React.memo
, bus perpieštas tik tuo atveju, jei pasikeis jo prop'ai. Kadangi onClick
prop'as (handleClick
) išlieka tas pats, Button
komponentas nereikalingai neperpiešiamas. Įsivaizduokite interaktyvią žemėlapių programą. Kiekvieną kartą, kai vartotojas sąveikauja, gali būti paveikta dešimtys mygtukų komponentų. Be useCallback
, šie mygtukai nereikalingai perpiešiami, sukurdami vėlavimo patirtį. Naudojant useCallback
, užtikrinama sklandesnė sąveika.
React.memo pristatymas: komponentų memoizavimas
React.memo
yra aukštesniojo eilės komponentas (HOC), kuris memoizuoja funkcinį komponentą. Jis neleidžia komponentui perpiešti, jei jo prop'ai nepasikeitė. Tai panašu į PureComponent
klasės komponentams.
Kada naudoti React.memo
- Grynieji komponentai: Kai komponento išvestis priklauso tik nuo jo prop'ų ir jis neturi jokios savo būsenos.
- Brangus atvaizdavimas: Kai komponento atvaizdavimo procesas yra kompiuteriniu požiūriu brangus.
- Dažnas perpiešimas: Kai komponentas dažnai perpiešiamas, net jei jo prop'ai nepasikeitė.
Kaip veikia React.memo
React.memo
apvynioja funkcinį komponentą ir paviršutiniškai palygina ankstesnius ir kitus prop'us. Jei prop'ai yra vienodi, komponentas nebus perpieštas.
Pavyzdys: vartotojo profilio rodymas
Sukurkime komponentą, kuris rodo vartotojo profilį. Naudosime React.memo
, kad išvengtume nereikalingų perpiešimų, jei vartotojo duomenys nepasikeitė.
import React from 'react';
function UserProfile({ user }) {
console.log('UserProfile perpieštas'); // Parodo, kada komponentas perpiešiamas
return (
Vardas: {user.name}
El. paštas: {user.email}
);
}
const MemoizedUserProfile = React.memo(UserProfile, (prevProps, nextProps) => {
// Pasirinktinė palyginimo funkcija (neprivaloma)
return prevProps.user.id === nextProps.user.id; // Perpiešti tik tuo atveju, jei pasikeičia vartotojo ID
});
function App() {
const [user, setUser] = React.useState({
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
});
const updateUser = () => {
setUser({ ...user, name: 'Jane Doe' }); // Keičiamas vardas
};
return (
);
}
export default App;
Šiame pavyzdyje MemoizedUserProfile
komponentas bus perpieštas tik tuo atveju, jei pasikeis user.id
prop'as. Net jei pasikeičia kitos user
objekto savybės (pvz., vardas ar el. paštas), komponentas nebus perpieštas, nebent ID būtų kitoks. Ši pasirinktinė palyginimo funkcija React.memo
leidžia tiksliai kontroliuoti, kada komponentas perpiešiamas. Apsvarstykite socialinės žiniasklaidos platformą su nuolat atnaujinamais vartotojų profiliais. Be React.memo
, pasikeitus vartotojo būsenai ar profilio nuotraukai, būtų visiškai perpieštas profilio komponentas, net jei pagrindinė vartotojo informacija išlieka ta pati. React.memo
leidžia atlikti tikslinius atnaujinimus ir žymiai pagerina našumą.
useMemo, useCallback ir React.memo derinimas
Šios trys technikos yra efektyviausios, kai naudojamos kartu. useMemo
memoizuoja brangius skaičiavimus, useCallback
memoizuoja funkcijas, o React.memo
memoizuoja komponentus. Derindami šias technikas, galite žymiai sumažinti nereikalingų perpiešimų skaičių savo React programoje.
Pavyzdys: sudėtingas komponentas
Sukurkime sudėtingesnį komponentą, kuris demonstruoja, kaip derinti šias technikas.
import React, { useState, useCallback, useMemo } from 'react';
function ListItem({ item, onUpdate, onDelete }) {
console.log(`ListItem ${item.id} perpieštas`); // Parodo, kada komponentas perpiešiamas
return (
{item.text}
);
}
const MemoizedListItem = React.memo(ListItem);
function List({ items, onUpdate, onDelete }) {
console.log('Sąrašas perpieštas'); // Parodo, kada komponentas perpiešiamas
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: `Atnaujinta ${item.text}` } : item
)
);
}, []);
const handleDelete = useCallback((id) => {
setItems((prevItems) => prevItems.filter((item) => item.id !== id));
}, []);
const memoizedItems = useMemo(() => items, [items]);
return (
);
}
export default App;
Šiame pavyzdyje:
useCallback
naudojamas memoizuoti funkcijashandleUpdate
irhandleDelete
, kad jos nebūtų sukurtos iš naujo su kiekvienu perpiešimu.useMemo
naudojamas memoizuoti masyvąitems
, kadList
komponentas nebūtų perpieštas, jei masyvo nuoroda nepasikeitė.React.memo
naudojamas memoizuotiListItem
irList
komponentus, kad jie nebūtų perpiešti, jei jų prop'ai nepasikeitė.
Šis technikų derinys užtikrina, kad komponentai perpiešiami tik esant būtinybei, o tai lemia didelius našumo patobulinimus. Įsivaizduokite didelio masto projekto valdymo įrankį, kuriame nuolat atnaujinami, trinami ir perstatomi užduočių sąrašai. Be šių optimizavimų, bet koks nedidelis užduočių sąrašo pakeitimas sukeltų perpiešimų kaskadą, dėl kurios programa būtų lėta ir nereaguojanti. Strategiškai naudodami useMemo
, useCallback
ir React.memo
, programa gali išlikti našia net ir esant sudėtingiems duomenims ir dažniems atnaujinimams.
Papildomos optimizavimo technikos
Nors useMemo
, useCallback
ir React.memo
yra galingi įrankiai, jie nėra vienintelės galimybės optimizuoti React našumą. Štai keletas papildomų technikų, į kurias reikia atsižvelgti:
- Kodo skaidymas: Padalinkite savo programą į mažesnius gabalus, kurie gali būti įkeliami pagal poreikį. Tai sumažina pradinį įkėlimo laiką ir pagerina bendrą našumą.
- Atsiliko įkėlimas: Įkelkite komponentus ir išteklius tik tada, kai jų reikia. Tai gali būti ypač naudinga vaizdams ir kitiems dideliems ištekliams.
- Virtualizavimas: Atvaizduokite tik matomą didelio sąrašo ar lentelės dalį. Tai gali žymiai pagerinti našumą dirbant su dideliais duomenų rinkiniais. Tokios bibliotekos kaip
react-window
irreact-virtualized
gali padėti tai padaryti. - Debouncing ir Throttling: Apribokite funkcijų vykdymo greitį. Tai gali būti naudinga tvarkant tokius įvykius kaip slinkimas ir dydžio keitimas.
- Nepakeičiamumas: Naudokite nepakeičiamas duomenų struktūras, kad išvengtumėte atsitiktinių mutacijų ir supaprastintumėte pakeitimų aptikimą.
Bendrieji optimizavimo aspektai
Optimizuojant React programas pasaulinei auditorijai, svarbu atsižvelgti į tokius veiksnius kaip tinklo delsos, įrenginio galimybės ir lokalizacija. Štai keletas patarimų:
- Turinio pristatymo tinklai (CDN): Naudokite CDN, kad pateiktumėte statinius išteklius iš vietų, esančių arčiau jūsų vartotojų. Tai sumažina tinklo delsą ir pagerina įkėlimo laiką.
- Vaizdų optimizavimas: Optimizuokite vaizdus skirtingiems ekrano dydžiams ir raiškoms. Naudokite suspaudimo metodus, kad sumažintumėte failų dydžius.
- Lokalizacija: Įkelkite tik būtinus kalbos išteklius kiekvienam vartotojui. Tai sumažina pradinį įkėlimo laiką ir pagerina vartotojo patirtį.
- Adaptacinis įkėlimas: Aptikite vartotojo tinklo ryšį ir įrenginio galimybes ir atitinkamai pakoreguokite programos veikimą. Pavyzdžiui, galite išjungti animacijas arba sumažinti vaizdo kokybę vartotojams, turintiems lėtus tinklo ryšius arba senesnius įrenginius.
Išvada
React programos našumo optimizavimas yra būtinas norint užtikrinti sklandų ir reaguojantį vartotojo patyrimą. Įvaldę tokias technikas kaip useMemo
, useCallback
ir React.memo
ir atsižvelgdami į globalias optimizavimo strategijas, galite sukurti didelio našumo React programas, kurios masteliu atitiktų įvairios vartotojų bazės poreikius. Nepamirškite profiliuoti savo programą, kad nustatytumėte našumo kliūtis, ir strategiškai taikykite šias optimizavimo technikas. Neoptimizuokite prieš laiką – sutelkite dėmesį į sritis, kuriose galite pasiekti didžiausią poveikį.
Šis vadovas suteikia tvirtą pagrindą React našumo optimizavimui suprasti ir įgyvendinti. Tęsdami React programų kūrimą, nepamirškite teikti pirmenybę našumui ir nuolat ieškoti naujų būdų, kaip pagerinti vartotojo patyrimą.