Išsamus vadovas, kaip optimizuoti React Context API naudojant useContext, siekiant pagerinti našumą ir mastelį didelėse programose.
React useContext: Context API naudojimo optimizavimas našumui
React Context API, pasiekiamas per useContext hook'ą, suteikia galingą mechanizmą dalintis duomenimis visame komponentų medyje, nereikalaujant rankiniu būdu perduoti props'ų per kiekvieną lygį. Nors tai suteikia didelį patogumą, netinkamas naudojimas gali sukelti našumo problemas, ypač didelėse ir sudėtingose programose. Šis vadovas gilinsis į efektyvias strategijas, kaip optimizuoti Context API naudojimą su useContext, užtikrinant, kad jūsų React programos išliktų našios ir mastelį atitinkančios.
Galimų našumo problemų supratimas
Pagrindinė problema slypi tame, kaip useContext sukelia pervaizdavimus (re-renders). Kai komponentas naudoja useContext, jis prenumeruoja pokyčius nurodytame kontekste. Bet koks konteksto reikšmės atnaujinimas, nepriklausomai nuo to, ar konkrečiam komponentui iš tikrųjų reikia atnaujintų duomenų, sukels komponento ir visų jo palikuonių pervaizdavimą. Tai gali lemti nereikalingus pervaizdavimus, kurie mažina našumą, ypač dirbant su dažnai atnaujinamais kontekstais ar dideliais komponentų medžiais.
Įsivaizduokite scenarijų, kuriame turite globalų temos kontekstą, naudojamą stiliui. Jei pasikeis net menka, nesusijusi duomenų dalis tame temos kontekste, kiekvienas komponentas, naudojantis šį kontekstą, nuo mygtukų iki ištisų maketų, bus pervaizduotas. Tai neefektyvu ir gali neigiamai paveikti vartotojo patirtį.
useContext optimizavimo strategijos
Galima pritaikyti kelias technikas, siekiant sumažinti useContext poveikį našumui. Išnagrinėsime šias strategijas, pateikdami praktinius pavyzdžius ir geriausias praktikas.
1. Detalus kontekstų kūrimas
Užuot kūrę vieną, monolitinį kontekstą visai savo programai, suskaidykite duomenis į mažesnius, konkretesnius kontekstus. Tai sumažina pervaizdavimų apimtį. Paveikti bus tik tie komponentai, kurie tiesiogiai priklauso nuo pasikeitusių duomenų konkrečiame kontekste.
Pavyzdys:
Užuot turėję vieną AppContext, kuriame laikomi vartotojo duomenys, temos nustatymai ir kita globali būsena, sukurkite atskirus kontekstus:
UserContext: Vartotojo informacijai (autentifikacijos būsena, vartotojo profilis ir t. t.).ThemeContext: Temos nustatymams (spalvos, šriftai ir t. t.).SettingsContext: Programos nustatymams (kalba, laiko juosta ir t. t.).
Šis metodas užtikrina, kad pokyčiai viename kontekste nesukels pervaizdavimų komponentuose, kurie priklauso nuo kitų, nesusijusių kontekstų.
2. Memoizacijos technikos: React.memo ir useMemo
React.memo: Apgaubkite komponentus, kurie naudoja kontekstą, su React.memo, kad išvengtumėte pervaizdavimų, jei jų props'ai nepasikeitė. Tai atlieka paviršutinišką (shallow) props'ų, perduotų komponentui, palyginimą.
Pavyzdys:
import React, { useContext } from 'react';
const ThemeContext = React.createContext({});
function MyComponent(props) {
const theme = useContext(ThemeContext);
return <div style={{ color: theme.textColor }}>{props.children}</div>;
}
export default React.memo(MyComponent);
Šiame pavyzdyje MyComponent bus pervaizduotas tik tada, kai pasikeis theme.textColor. Tačiau React.memo atlieka paviršutinišką palyginimą, kurio gali nepakakti, jei konteksto reikšmė yra sudėtingas objektas, kuris dažnai keičiamas. Tokiais atvejais apsvarstykite galimybę naudoti useMemo.
useMemo: Naudokite useMemo, norėdami memoizuoti išvestines reikšmes iš konteksto. Tai apsaugo nuo nereikalingų skaičiavimų ir užtikrina, kad komponentai būtų pervaizduojami tik tada, kai pasikeičia konkreti reikšmė, nuo kurios jie priklauso.
Pavyzdys:
import React, { useContext, useMemo } from 'react';
const MyContext = React.createContext({});
function MyComponent() {
const contextValue = useContext(MyContext);
// Memoize the derived value
const importantValue = useMemo(() => {
return contextValue.item1 + contextValue.item2;
}, [contextValue.item1, contextValue.item2]);
return <div>{importantValue}</div>;
}
export default MyComponent;
Čia importantValue perskaičiuojama tik tada, kai pasikeičia contextValue.item1 arba contextValue.item2. Jei pasikeis kitos `contextValue` savybės, MyComponent nebus pervaizduotas be reikalo.
3. Selektorių funkcijos
Sukurkite selektorių funkcijas, kurios ištraukia tik reikiamus duomenis iš konteksto. Tai leidžia komponentams prenumeruoti tik konkrečias duomenų dalis, kurių jiems reikia, o ne visą konteksto objektą. Ši strategija papildo detalų kontekstų kūrimą ir memoizaciją.
Pavyzdys:
import React, { useContext } from 'react';
const UserContext = React.createContext({});
// Selector function to extract the username
const selectUsername = (userContext) => userContext.username;
function UsernameDisplay() {
const username = selectUsername(useContext(UserContext));
return <p>Username: {username}</p>;
}
export default UsernameDisplay;
Šiame pavyzdyje UsernameDisplay pervaizduojamas tik tada, kai pasikeičia username savybė UserContext kontekste. Šis metodas atsaiso komponentą nuo kitų savybių, saugomų `UserContext`.
4. Individualūs hook'ai konteksto naudojimui
Inkapsuliuokite konteksto naudojimo logiką į individualius hook'us. Tai suteikia švaresnį ir labiau pakartotinai naudojamą būdą pasiekti konteksto reikšmes ir taikyti memoizaciją ar selektorių funkcijas. Tai taip pat palengvina testavimą ir priežiūrą.
Pavyzdys:
import React, { useContext, useMemo } from 'react';
const ThemeContext = React.createContext({});
// Custom hook for accessing the theme color
function useThemeColor() {
const theme = useContext(ThemeContext);
// Memoize the theme color
const themeColor = useMemo(() => theme.color, [theme.color]);
return themeColor;
}
function MyComponent() {
const themeColor = useThemeColor();
return <div style={{ color: themeColor }}>Hello, World!</div>;
}
export default MyComponent;
useThemeColor hook'as inkapsuliuoja logiką, skirtą pasiekti theme.color ir ją memoizuoti. Tai palengvina šios logikos pakartotinį naudojimą keliuose komponentuose ir užtikrina, kad komponentas būtų pervaizduojamas tik tada, kai pasikeičia theme.color.
5. Būsenos valdymo bibliotekos: alternatyvus požiūris
Sudėtingiems būsenos valdymo scenarijams apsvarstykite galimybę naudoti specializuotas būsenos valdymo bibliotekas, tokias kaip Redux, Zustand ar Jotai. Šios bibliotekos siūlo pažangesnes funkcijas, tokias kaip centralizuotas būsenos valdymas, nuspėjami būsenos atnaujinimai ir optimizuoti pervaizdavimo mechanizmai.
- Redux: Subrendusi ir plačiai naudojama biblioteka, kuri suteikia nuspėjamą būsenos konteinerį JavaScript programoms. Ji reikalauja daugiau paruošiamojo kodo, bet siūlo puikius derinimo įrankius ir didelę bendruomenę.
- Zustand: Mažas, greitas ir mastelį atitinkantis būsenos valdymo sprendimas, naudojantis supaprastintus flux principus. Jis žinomas dėl savo paprasto naudojimo ir minimalaus paruošiamojo kodo.
- Jotai: Primityvus ir lankstus būsenos valdymas, skirtas React. Jis suteikia paprastą ir intuityvų API globaliai būsenai valdyti su minimaliu paruošiamuoju kodu.
Šios bibliotekos gali būti geresnis pasirinkimas valdant sudėtingą programos būseną, ypač kai susiduriama su dažnais atnaujinimais ir painiomis duomenų priklausomybėmis. Context API puikiai tinka išvengti „prop drilling“, tačiau specializuotos būsenos valdymo priemonės dažnai sprendžia našumo problemas, kylančias dėl globalios būsenos pokyčių.
6. Nekintamos duomenų struktūros
Naudodami sudėtingus objektus kaip konteksto reikšmes, pasinaudokite nekintamomis duomenų struktūromis. Nekintamos duomenų struktūros užtikrina, kad objekto pakeitimai sukuria naują objekto egzempliorių, o ne modifikuoja esamą. Tai leidžia React efektyviai aptikti pakeitimus ir išvengti nereikalingų pervaizdavimų.
Bibliotekos, tokios kaip Immer ir Immutable.js, gali padėti jums lengviau dirbti su nekintamomis duomenų struktūromis.
Pavyzdys naudojant Immer:
import React, { createContext, useState, useContext, useCallback } from 'react';
import { useImmer } from 'use-immer';
const MyContext = createContext();
function MyProvider({ children }) {
const [state, updateState] = useImmer({
item1: 'value1',
item2: 'value2',
});
const updateItem1 = useCallback((newValue) => {
updateState((draft) => {
draft.item1 = newValue;
});
}, [updateState]);
return (
<MyContext.Provider value={{ state, updateItem1 }}>
{children}
</MyContext.Provider>
);
}
function MyComponent() {
const { state, updateItem1 } = useContext(MyContext);
return (
<div>
<p>Item 1: {state.item1}</p>
<button onClick={() => updateItem1('new value')}>Update Item 1</button>
</div>
);
}
export { MyContext, MyProvider, MyComponent };
Šiame pavyzdyje useImmer užtikrina, kad būsenos atnaujinimai sukuria naują būsenos objektą, sukeliant pervaizdavimus tik tada, kai tai būtina.
7. Būsenos atnaujinimų grupavimas
React automatiškai sugrupuoja kelis būsenos atnaujinimus į vieną pervaizdavimo ciklą. Tačiau tam tikrose situacijose gali prireikti rankiniu būdu grupuoti atnaujinimus. Tai ypač naudinga dirbant su asinchroninėmis operacijomis ar keliais atnaujinimais per trumpą laiką.
Galite naudoti ReactDOM.unstable_batchedUpdates (pasiekiama React 18 ir ankstesnėse versijose, ir paprastai nereikalinga su automatiniu grupavimu React 18+), kad rankiniu būdu grupuotumėte atnaujinimus.
8. Nereikalingų konteksto atnaujinimų vengimas
Įsitikinkite, kad atnaujinate konteksto reikšmę tik tada, kai yra realių duomenų pakeitimų. Venkite be reikalo atnaujinti kontekstą su ta pačia reikšme, nes tai vis tiek sukels pervaizdavimus.
Prieš atnaujindami kontekstą, palyginkite naują reikšmę su ankstesne, kad įsitikintumėte, jog yra skirtumas.
Realaus pasaulio pavyzdžiai iš skirtingų šalių
Panagrinėkime, kaip šios optimizavimo technikos gali būti taikomos skirtinguose scenarijuose įvairiose šalyse:
- El. prekybos platforma (visame pasaulyje): El. prekybos platforma naudoja
CartContextvartotojo pirkinių krepšeliui valdyti. Be optimizavimo, kiekvienas puslapio komponentas galėtų būti pervaizduotas, kai į krepšelį pridedama prekė. Naudojant selektorių funkcijas irReact.memo, pervaizduojama tik krepšelio suvestinė ir susiję komponentai. Naudojant bibliotekas, tokias kaip Zustand, galima efektyviai centralizuoti krepšelio valdymą. Tai taikoma visame pasaulyje, nepriklausomai nuo regiono. - Finansų prietaisų skydelis (Jungtinės Valstijos, Jungtinė Karalystė, Vokietija): Finansų prietaisų skydelis rodo realaus laiko akcijų kainas ir portfelio informaciją.
StockDataContextpateikia naujausius akcijų duomenis. Siekiant išvengti per didelių pervaizdavimų,useMemonaudojamas memoizuoti išvestines reikšmes, pavyzdžiui, bendrą portfelio vertę. Tolesnis optimizavimas galėtų apimti selektorių funkcijų naudojimą, norint ištraukti konkrečius duomenų taškus kiekvienai diagramai. Bibliotekos, tokios kaip Recoil, taip pat gali būti naudingos. - Socialinės medijos programa (Indija, Brazilija, Indonezija): Socialinės medijos programa naudoja
UserContextvartotojo autentifikacijai ir profilio informacijai valdyti. Naudojamas detalus kontekstų kūrimas, siekiant atskirti vartotojo profilio kontekstą nuo autentifikacijos konteksto. Nekintamos duomenų struktūros naudojamos siekiant užtikrinti efektyvų pakeitimų aptikimą. Bibliotekos, tokios kaip Immer, gali supaprastinti būsenos atnaujinimus. - Kelionių rezervavimo svetainė (Japonija, Pietų Korėja, Kinija): Kelionių rezervavimo svetainė naudoja
SearchContextpaieškos kriterijams ir rezultatams valdyti. Individualūs hook'ai naudojami inkapsuliuoti logiką, skirtą pasiekti ir memoizuoti paieškos rezultatus. Būsenos atnaujinimų grupavimas naudojamas našumui pagerinti, kai vienu metu taikomi keli filtrai.
Praktinės įžvalgos ir geriausios praktikos
- Profiluokite savo programą: Naudokite React DevTools, kad nustatytumėte komponentus, kurie dažnai pervaizduojami.
- Pradėkite nuo detalių kontekstų: Suskaidykite savo globalią būseną į mažesnius, lengviau valdomus kontekstus.
- Strategiškai taikykite memoizaciją: Naudokite
React.memoiruseMemo, kad išvengtumėte nereikalingų pervaizdavimų. - Naudokite selektorių funkcijas: Ištraukite tik reikiamus duomenis iš konteksto.
- Apsvarstykite būsenos valdymo bibliotekas: Sudėtingam būsenos valdymui išbandykite bibliotekas, tokias kaip Redux, Zustand ar Jotai.
- Prisitaikykite prie nekintamų duomenų struktūrų: Naudokite bibliotekas, tokias kaip Immer, kad supaprastintumėte darbą su nekintamais duomenimis.
- Stebėkite ir optimizuokite: Nuolat stebėkite savo programos našumą ir prireikus optimizuokite konteksto naudojimą.
Išvados
React Context API, naudojamas protingai ir optimizuotas aptartomis technikomis, siūlo galingą ir patogų būdą dalintis duomenimis visame komponentų medyje. Suprasdami galimas našumo problemas ir įgyvendindami tinkamas optimizavimo strategijas, galite užtikrinti, kad jūsų React programos išliktų našios, mastelį atitinkančios ir lengvai prižiūrimos, nepriklausomai nuo jų dydžio ar sudėtingumo.
Nepamirškite visada profiliuoti savo programą ir nustatyti sritis, kurioms reikia optimizavimo. Pasirinkite strategijas, kurios geriausiai atitinka jūsų konkrečius poreikius ir kontekstą. Laikydamiesi šių gairių, galite efektyviai išnaudoti useContext galią ir kurti aukšto našumo React programas, kurios suteikia išskirtinę vartotojo patirtį.