Memoisering är en optimeringsteknik som liknar cachning. Det fungerar genom att lagra de tidigare resultaten av ett funktionsanrop och använda dessa resultat nästa gång funktionen körs. Det är särskilt användbart i beräkningstunga appar som upprepar funktionsanrop på samma parametrar.
Du kan använda memoisering i vanlig JavaScript och även i React, på några olika sätt.
Memoisering i JavaScript
För att memorera en funktion i JavaScript måste du lagra resultaten av den funktionen i en cache. Cachen kan vara ett objekt med argumenten som nycklar och resultaten som värden.
När du anropar den här funktionen kontrollerar den först om resultatet finns i cachen innan den körs. Om det är det returnerar det de cachade resultaten. Annars körs den.
Tänk på den här funktionen:
fungerafyrkant(num) {
lämna tillbaka num * num
}
Funktionen tar in ett argument och returnerar dess kvadrat.
För att köra funktionen, ring den med ett nummer så här:
fyrkant(5) // 25
Med 5 som argument kommer square() att köras ganska snabbt. Men om du skulle räkna ut kvadraten på 70 000 skulle det bli en märkbar fördröjning. Inte mycket men en försening ändå. Nu, om du skulle ringa funktionen flera gånger och passera 70 000, skulle du uppleva en fördröjning i varje samtal.
Du kan eliminera denna fördröjning genom att använda memoisering.
konst memoizedSquare = () => {
låta cache = {};
lämna tillbaka (antal) => {
om (antal in cache) {
console.log('Återanvänder cachelagrat värde');
lämna tillbaka cache[num];
} annan {
console.log('Beräknar resultat');
låta resultat = num * num;
// cache de nyresultatvärdeförNästatid
cache[num] = resultat;
lämna tillbaka resultat;
}
}
}
I det här exemplet kontrollerar funktionen om den har beräknat resultatet tidigare, genom att kontrollera om det finns i cacheobjektet. Om den har det returnerar det det redan beräknade värdet.
När funktionen får ett nytt nummer, beräknar den ett nytt värde och lagrar resultaten i cachen innan den returneras.
Återigen är det här exemplet ganska enkelt, men det förklarar hur memoisering skulle fungera för att förbättra prestandan för ett program.
Du bör bara memorera rena funktioner. Dessa funktioner returnerar samma resultat när du skickar in samma argument. Om du använder memoisering på orena funktioner kommer du inte att förbättra prestandan utan öka din omkostnad. Det beror på att du väljer hastighet framför minne varje gång du memorerar en funktion.
Memoisering i React
Om du vill optimera React-komponenter tillhandahåller React memoisering genom useMemo()-kroken, React.memo och useCallBack().
Använda useMemo()
useMemo() är en Reagera krok som accepterar en funktion och en beroendematris.
konst memoizedValue = useMemo(() => computeExpensiveValue (a, b), [a, b]);
Den memorerar värdet som returneras från den funktionen. Värdena i beroendematrisen bestämmer när funktionen exekveras. Först när de ändras exekveras funktionen igen.
Till exempel har följande app-komponent ett minnesvärde som kallas resultat.
importera { useMemo } från "reagera"
fungeraApp(värde) {
konst kvadrat = (värde) => {
lämna tillbaka värde * värde
}
konst resultat = användMemo(
() => kvadrat (värde),
[ värde ]
);
lämna tillbaka (
<div>{resultat (5)}</div>
)
}
App-komponenten anropar square() vid varje rendering. Prestandan försämras om App-komponenten renderas många gånger pga Reagera rekvisita ändring eller statusuppdatering, speciellt om square()-funktionen är dyr.
Men eftersom useMemo() cachar de returnerade värdena, exekveras inte kvadratfunktionen i varje omrendering om inte argumenten i beroendematrisen ändras.
Använda React.memo()
React.memo() är en högre ordningskomponent som accepterar en React-komponent och en funktion som argument. Funktionen bestämmer när komponenten ska uppdateras.
Funktionen är valfri och om den inte tillhandahålls gör React.memo en ytlig kopia av jämförelse av komponentens nuvarande rekvisita med dess tidigare rekvisita. Om rekvisitan är annorlunda utlöser det en uppdatering. Om rekvisita är desamma, hoppar den över återrenderingen och återanvänder de memoiserade värdena.
Den valfria funktionen accepterar föregående rekvisita och nästa rekvisita som argument. Du kan sedan uttryckligen jämföra dessa rekvisita för att bestämma om du ska uppdatera komponenten eller inte.
Reagera.PM(Komponent, [areEqual (prevProps, nextProps)])
Låt oss först titta på ett exempel utan det valfria funktionsargumentet. Nedan finns en komponent som heter Kommentarer som accepterar namn och e-postrekvisita.
fungeraKommentarer ({namn, kommentar, gillar}) {
lämna tillbaka (
<div>
<sid>{namn}</s>
<sid>{kommentar}</s>
<sid>{gillar}</s>
</div>
)
}
Den memoariserade kommentarskomponenten kommer att ha React.memo lindad runt sig så här:
konst MemoizedComment = React.memo (Kommentar)
Du kan anropa och sedan kalla det som vilken annan React-komponent som helst.
<MemoizedComment name="Mary" kommentar="Memoization är bra" gillar=1/>
Om du vill utföra rekvisitajämförelsen själv, skicka följande funktion till React.memo som det andra argumentet.
importera Reagera från "reagera"
fungeracheckCommentProps(prevProps, nextProps) {
lämna tillbaka prevProps.name nästaProps.name
&& prevProps.comment nextProps.comment
&& prevProps.likes nextProps.likes
}
konst MemoizedComment = React.memo (Kommentarer, checkCommentProps)
Om checkProfileProps returnerar true uppdateras inte komponenten. Annars renderas den om.
Den anpassade funktionen är användbar när du vill anpassa återrenderingen. Du kan till exempel använda den för att uppdatera komponenten Kommentarer endast när antalet likes ändras.
Till skillnad från useMemo()-kroken som memorerar endast det returnerade värdet av en funktion, memorerar React.memo hela funktionen.
Använd endast React.memo för rena komponenter. För att minska jämförelsekostnaderna bör du bara memorera komponenter vars rekvisita ändras ofta.
Använda useCallBack()
Du kan använda useCallBack()-kroken för att memorera funktionskomponenter.
konst memoizedCallback = användCallback(
() => {
göra något (a, b);
},
[a, b],
);
Funktionen uppdateras endast när värdena i beroendematrisen ändras. Kroken fungerar som useMemo()-återuppringningen, men den memorerar funktionskomponenten mellan renderingar istället för att memorera värden.
Betrakta följande exempel på en memoiserad funktion som anropar ett API.
importera { useCallback, useEffect } från "reagera";
konst Komponent = () => {
konst getData = useCallback(() => {
console.log('anropa ett API');
}, []);
useEffect(() => {
hämta data();
}, [hämta data]);
};
GetData()-funktionen anropad i useEffect kommer att anropas igen endast när getData-värdet ändras.
Bör du memorera?
I den här handledningen lärde du dig vad memoization är, dess fördelar och hur du implementerar det i JavaScript och React. Du bör dock veta att React redan är snabb. I de flesta fall lägger memorering av komponenter eller värden till jämförelsekostnader och förbättrar inte prestandan. På grund av detta, memorera bara dyra komponenter.
React 18 introducerade också nya krokar som useId, useTransition och useInsertionEffect. Du kan använda dessa för att förbättra prestandan och användarupplevelsen av React-applikationer.