React Native Academy · Oppitunti

useCallback ja useMemo suorituskyvyn parantamiseen

Välimuistittakaa callback-funktiot useCallbackilla tarpeettomien alikomponenttien uudelleenrenderöintien estämiseksi ja tallentakaa raskaat lasketut arvot välimuistiin useMemolla.

Oppitunti 3/413 vaihetta

useCallback ja useMemo suorituskyvyn parantamiseen on ilmainen React Native Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu React Native Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. React Native Academy-kurssilla on yhteensä 4 oppituntia.

Uudelleenrenderöinnin ongelma

Aina kun komponentti renderöidään Reactissa uudelleen, kaikki funktion rungon sisällä luodut arvot luodaan uudelleen. Näihin kuuluvat oliot, taulukot ja ennen kaikkea funktiot. Jos uudelleen luotu funktio tai arvo välitetään lapsikomponentille propsina, lapsi näkee uuden viitteen ja renderöityy uudelleen, vaikka looginen arvo ei olisi muuttunut.

Mikä on useCallback?

useCallback(fn, deps) palauttaa callback-funktion memoisoidun version, joka muuttuu vain, jos jokin riippuvuuksista on muuttunut. Callbackin kääriminen useCallbackiin säilyttää saman funktioviitteen renderöintien välillä ja estää näin tarpeettomat uudelleenrenderöinnit lapsikomponenteissa, jotka vastaanottavat sen propsina.

import { useCallback } from 'react';

function Parent() {
  const [count, setCount] = useState(0);

  // handlePress is the SAME function reference between renders
  // as long as count does not change
  const handlePress = useCallback(() => {
    console.log('Pressed, count is:', count);
  }, [count]);

  return <Child onPress={handlePress} />;
}

useCallback ja React.memo

useCallback on tehokkaimmillaan, kun se yhdistetään lapsikomponentissa React.memo-funktioon. Ilman React.memoa lapsi renderöityy joka tapauksessa uudelleen propien viitteiden yhtäsuuruudesta riippumatta. React.memo lapsikomponentissa ja useCallback vanhemman callbackissa estävät uudelleenrenderöinnit, kun toiminta tai tiedot eivät ole muuttuneet.

const ChildButton = React.memo(({ onPress, label }) => (
  <Button title={label} onPress={onPress} />
));

function Parent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  // ChildButton will NOT re-render when text changes
  const handleCount = useCallback(() => setCount(c => c + 1), []);

  return (
    <>
      <TextInput value={text} onChangeText={setText} />
      <ChildButton label='Count' onPress={handleCount} />
    </>
  );
}

Mikä on useMemo?

useMemo(computeFn, deps) memo­isoi kalliin laskutoimituksen tuloksen. React kutsuu computeFn-funktiota ensimmäisellä renderöinnillä ja tallentaa sen palauttaman arvon välimuistiin. Seuraavilla renderöinneillä palautetaan välimuistissa oleva arvo, ellei jokin riippuvuus ole muuttunut. Näin raskaita laskutoimituksia ei tarvitse toistaa jokaisella renderöinnillä.

import { useMemo } from 'react';

function ProductList({ products, category }) {
  // Only recomputes when products or category changes
  const filtered = useMemo(
    () => products.filter((p) => p.category === category),
    [products, category]
  );

  return <FlatList data={filtered} renderItem={renderItem} />;
}

useMemo vakaiden olioviitteiden luomiseen

JSX:ssä suoraan luodut oliot ja taulukot ovat uusia viitteitä jokaisella renderöinnillä. Jos ne välitetään memoisoidulle lapsikomponentille, ne kumoavat memoisaation hyödyn. Käärikää ne useMemo-hookiin luodaksenne vakaan viitteen, joka muuttuu vain taustalla olevien tietojen muuttuessa. Tämä on erityisen tärkeää tyylitaulukoille ja konfiguraatio-olioille.

function Chart({ data, color }) {
  // New object on every render without useMemo
  const chartConfig = useMemo(() => ({
    backgroundColor: color,
    dataPoints: data.map((d) => d.value),
  }), [data, color]);

  return <ChartComponent config={chartConfig} />;
}

Riippuvuustaulukot: niiden oikea määrittäminen

Sekä useCallback että useMemo edellyttävät täsmällisiä riippuvuustaulukoita. Sisällyttäkää niihin kaikki komponentin skoopin arvot, joita memoisoidussa funktiossa tai laskutoimituksessa käytetään. Puuttuva riippuvuus saa memoisoidun arvon käyttämään vanhentunutta sulkeumaa, kun taas liian monien riippuvuuksien ilmoittaminen aiheuttaa tarpeettomia uudelleenlaskentoja. ESLintin exhaustive-deps-sääntö auttaa varmistamaan oikeellisuuden.

// Wrong: missing userId dependency — stale closure bug
const fetchUser = useCallback(() => fetch('/user/' + userId), []);

// Correct: userId is listed
const fetchUser = useCallback(() => fetch('/user/' + userId), [userId]);

Milloin useCallbackia EI pidä käyttää

useCallbackilla on hintansa: React tallentaa funktion muistiin ja tarkistaa riippuvuustaulukon jokaisella renderöinnillä. Yksinkertaisissa käsittelijöissä, joita ei välitetä memoisoiduille lapsikomponenteille, useCallbackin aiheuttama kuormitus on hyötyä suurempi. Käyttäkää sitä harkiten – vain silloin, kun lapsikomponentti on kääritty React.memolla ja propsien yhtäsuuruudella on merkitystä suorituskyvyn kannalta.

// Unnecessary: Button re-renders anyway; no child is memoized
const handlePress = useCallback(() => setVisible(true), []);

// Fine without useCallback in this case
const handlePress = () => setVisible(true);

useMemo kalliisiin muunnoksiin

Käyttäkää useMemo-hookia, kun laskutoimitus vie huomattavasti aikaa, kuten suurten taulukoiden lajittelussa, monimutkaisten tietojen jäsentämisessä tai tilastollisissa laskelmissa. Nyrkkisääntönä voidaan pitää, että jos laskutoimitus kestää yli millisekunnin ja suoritetaan jokaisella renderöinnillä, sen memoisaatiota kannattaa harkita. Yksinkertaisissa toiminnoissa, kuten kahden luvun yhteenlaskussa, memoisaation aiheuttama kuormitus on laskutoimitusta suurempi.

const sortedAndFiltered = useMemo(() => {
  return items
    .filter((item) => item.status === selectedStatus)
    .sort((a, b) => b.createdAt - a.createdAt)
    .slice(0, 100);
}, [items, selectedStatus]);

useCallback FlatListin renderItem-funktiolle

FlatListin renderItem-funktion kääriminen useCallback-hookiin estää uuden funktioviitteen luomisen jokaisella vanhemman renderöinnillä. Muutoin jokainen näkyvissä oleva FlatList-rivi renderöityisi uudelleen. Tämä on yksi merkittävimmistä suorituskykyparannuksista React Native -sovelluksissa, joissa käytetään paljon luetteloita.

const renderItem = useCallback(({ item }) => (
  <ProductCard
    product={item}
    onPress={handleSelectProduct}
  />
), [handleSelectProduct]); // handleSelectProduct also memoized

<FlatList
  data={products}
  renderItem={renderItem}
  keyExtractor={(item) => item.id}
/>

Vaikutuksen mittaaminen

Ennen kuin lisäätte memoisaation kaikkialle, mitatkaa sen todellinen vaikutus React DevTools Profilerilla. Tallentakaa toiminto, tarkastelkaa liekkikaaviota tarpeettomasti uudelleenrenderöityvien komponenttien tunnistamiseksi ja lisätkää useCallback tai useMemo vain kohtiin, joissa profiler osoittaa todellisen pullonkaulan. Ennenaikainen optimointi lisää koodin monimutkaisuutta ilman mitattavaa hyötyä.

Yhteenvetovertailu

Muistakaa keskeinen ero: useCallback memo­isoi funktion (estää funktioviitteen luomisen uudelleen), kun taas useMemo memo­isoi lasketun arvon (estää kalliin laskutoimituksen suorittamisen uudelleen). Molemmat vastaanottavat riippuvuustaulukon ja laskevat arvon uudelleen vain, kun luetellut riippuvuudet muuttuvat.

// useCallback — memoize a function
const fn = useCallback(() => doSomething(a, b), [a, b]);

// useMemo — memoize a computed value
const val = useMemo(() => computeExpensive(a, b), [a, b]);

// Relationship: useCallback(fn, deps) === useMemo(() => fn, deps)

Pikatarkistus

Testatkaa, miten hyvin ymmärrätte tämän oppitunnin useCallback- ja useMemo-hookien käytön suorituskyvyn parantamisessa.

Oppitunnin kertaus

Tässä oppitunnissa opitte, että useCallback memo­isoi funktioviitteen tarpeettomien lapsikomponenttien uudelleenrenderöintien estämiseksi, useMemo memo­isoi kalliin lasketun arvon, jotta laskentaa ei tarvitse toistaa jokaisella renderöinnillä ja molemmat toimivat parhaiten yhdessä React.memon ja täsmällisten riippuvuustaulukoiden kanssa. Seuraavaksi tutustumme mukautettujen hookien kirjoittamiseen tilallisen logiikan jakamiseksi komponenttien välillä.

Aloita maksutta

Opi JavaScript tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
30
Oppitunnit
120

Usein kysytyt kysymykset

Onko oppitunti ”useCallback ja useMemo suorituskyvyn parantamiseen” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa React Native Academy-oppimispolun 3 oppituntia, myös oppitunnin “useCallback ja useMemo suorituskyvyn parantamiseen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. React Native Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”useCallback ja useMemo suorituskyvyn parantamiseen”?

Välimuistittakaa callback-funktiot useCallbackilla tarpeettomien alikomponenttien uudelleenrenderöintien estämiseksi ja tallentakaa raskaat lasketut arvot välimuistiin useMemolla. Harjoittelet React Native Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni React Native Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin React Native Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”useCallback ja useMemo suorituskyvyn parantamiseen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä React Native Academy-oppitunnilla?

Kyllä. Jokainen React Native Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. useRef DOM-solmuille ja muuttuviin arvoihin
  2. useReducer monimutkaiseen tilalogiikkaan
  3. useCallback ja useMemo suorituskyvyn parantamiseen
  4. Mukautettujen hookien kirjoittaminen
← Takaisin: React Native Academy