javascript - useMemo vs. useEffect + useState
Er det noen fordeler med å bruke useMemo (f.eks. for et intensivt funksjonskall) i stedet for å bruke en kombinasjon av useEffect og useState?
Her er to egendefinerte hooks som fungerer akkurat likt ved første øyekast, bortsett fra at useMemos returverdi er null ved første rendering:
useEffect & useState
import { expensiveCalculation } from "foo";
function useCalculate(someNumber: number): number | null {
const [result, setResult] = useState<number | null>(null);
useEffect(() => {
setResult(expensiveCalculation(someNumber));
}, [someNumber]);
return result;
}
useMemo
import { expensiveCalculation } from "foo";
function useCalculateWithMemo(someNumber: number): number {
return useMemo(() => {
return expensiveCalculation(someNumber);
}, [someNumber]);
};
Begge beregner resultatet hver gang deres parameter someNumber endres, hvor slår memoizationen til i useMemo inn?
Svar #1
Det useEffect og setState vil forårsake ekstra gjengivelser ved hver endring: den første gjengivelsen vil «ligge etter» med utdaterte data, og deretter vil den umiddelbart sette opp en ekstra gjengivelse med de nye dataene.
Anta at vi har:
// Maybe I'm running this on a literal potato
function expensiveCalculation(x) { return x + 1; };
La oss anta at x er opprinnelig 0:
- Versjonen med
useMemogjengir umiddelbart1. - Versjonen med
useEffectrendrernull, deretter, etter at komponenten rendrer, kjører effekten, endrer tilstanden og setter opp en ny render med1.
Da, hvis vi endrer x til 2:
- Den
useMemokjører og3blir gjengitt. - Versjonen med
useEffectkjører, og gjengir1igjen, deretter utløses effekten og komponenten kjører på nytt med den riktige verdien3.
Når det gjelder hvor ofte expensiveCalculation kjører, har de to identisk oppførsel, men useEffect-versjonen forårsaker dobbelt så mye rendering, noe som er dårlig for ytelsen av andre grunner.
I tillegg er useMemo-versjonen bare renere og mer lesbar, etter min mening. Den introduserer ikke unødvendig muterbar tilstand og har færre bevegelige deler.
Så det er bedre for deg å bare bruke useMemo her.
Svar #2
Jeg tror det er to hovedpunkter du bør vurdere når du velger mellom dem.
- Tidspunkt når funksjonen ble kalt.
useEffect ble kalt etter at komponenten har blitt gjengitt, slik at du kan få tilgang til DOM fra den. For eksempel er dette viktig hvis du vil få tilgang til DOM-elementer via refs.
- Semantiske garantier.
useEffect garanterer at det ikke vil bli utløst hvis avhengighetene ikke har endret seg. useMemo gir ikke slike garantier.
Som angitt i React-dokumentasjonen, bør du vurdere useMemo som en ren optimaliseringsteknikk. Programmet ditt bør fortsatt fungere korrekt selv om du erstatter useMemo med et vanlig funksjonskall.
useEffect + useState kan brukes til å kontrollere oppdateringer. Selv for å bryte opp sirkulære avhengigheter og forhindre uendelige oppdateringssløyfer.
Svar #3
Jeg vil si at bortsett fra den asynkrone naturen, kan det være noen forskjeller når det gjelder hvordan de er designet.
useEffect er et samleanrop, asynkront eller ikke, det blir samlet etter at alle komponenter er rendret.
useMemo er et lokalt kall, som kun har noe å gjøre med denne komponenten. Du kan bare tenke på useMemo som en annen tildelingssetning med fordeler ved å bruke tildelingen fra siste oppdatering.
Dette betyr at useMemo er mer presserende, deretter useLayoutEffect og til slutt useEffect.