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 useMemo gjengir umiddelbart 1.
  • Versjonen med useEffect rendrer null, deretter, etter at komponenten rendrer, kjører effekten, endrer tilstanden og setter opp en ny render med 1.

Da, hvis vi endrer x til 2:

  • Den useMemo kjører og 3 blir gjengitt.
  • Versjonen med useEffect kjører, og gjengir 1 igjen, deretter utløses effekten og komponenten kjører på nytt med den riktige verdien 3.

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.

  1. 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.

  1. 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.

Relaterte artikler