Eesti

Õppige, kuidas efektiivselt kasutada Reacti efekti puhastusfunktsioone, et vältida mälulekkeid ja optimeerida oma rakenduse jõudlust. Põhjalik juhend Reacti arendajatele.

Reacti efekti puhastus: Meisterlik mälulekete ennetamine

Reacti useEffect hook on võimas tööriist kõrvalmõjude haldamiseks funktsionaalsetes komponentides. Kuid valesti kasutamisel võib see põhjustada mälulekkeid, mis mõjutavad teie rakenduse jõudlust ja stabiilsust. See põhjalik juhend süveneb Reacti efekti puhastamise peensustesse, pakkudes teile teadmisi ja praktilisi näiteid mälulekete ennetamiseks ja vastupidavamate Reacti rakenduste kirjutamiseks.

Mis on mälulekked ja miks on need halvad?

Mäluleke tekib siis, kui teie rakendus eraldab mälu, kuid ei suuda seda vabastada süsteemile tagasi, kui seda enam ei vajata. Aja jooksul need vabastamata mäluplokid kuhjuvad, tarbides järjest rohkem süsteemi ressursse. Veebirakendustes võivad mälulekked avalduda järgmiselt:

Reactis tekivad mälulekked sageli useEffect hookides, kui tegeletakse asünkroonsete operatsioonide, tellimuste või sündmuste kuulajatega. Kui neid operatsioone ei puhastata korralikult, kui komponent eemaldatakse või uuesti renderdatakse, võivad need taustal edasi töötada, tarbides ressursse ja põhjustades potentsiaalselt probleeme.

useEffect ja kõrvalmõjude mõistmine

Enne efekti puhastamisse süvenemist vaatame lühidalt üle useEffect eesmärgi. useEffect hook võimaldab teil teostada kõrvalmõjusid oma funktsionaalsetes komponentides. Kõrvalmõjud on operatsioonid, mis suhtlevad välismaailmaga, näiteks:

useEffect hook võtab vastu kaks argumenti:

  1. Funktsioon, mis sisaldab kõrvalmõju.
  2. Valikuline sõltuvuste massiiv.

Kõrvalmõju funktsioon käivitatakse pärast komponendi renderdamist. Sõltuvuste massiiv ütleb Reactile, millal efekti uuesti käivitada. Kui sõltuvuste massiiv on tühi ([]), käivitub efekt ainult üks kord pärast esialgset renderdamist. Kui sõltuvuste massiiv on ära jäetud, käivitub efekt pärast iga renderdamist.

Efekti puhastamise tähtsus

Reactis mälulekete vältimise võti on kõrvalmõjude puhastamine, kui neid enam ei vajata. Siin tulebki mängu puhastusfunktsioon. useEffect hook võimaldab teil tagastada funktsiooni kõrvalmõju funktsioonist. See tagastatud funktsioon ongi puhastusfunktsioon ja see käivitatakse siis, kui komponent eemaldatakse või enne efekti uuesti käivitamist (sõltuvuste muutumise tõttu).

Siin on põhiline näide:


import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    console.log('Effect ran');

    // See on puhastusfunktsioon
    return () => {
      console.log('Cleanup ran');
    };
  }, []); // Tühi sõltuvuste massiiv: käivitub ainult üks kord ühendamisel

  return (
    

Count: {count}

); } export default MyComponent;

Selles näites käivitub console.log('Effect ran') üks kord, kui komponent ühendatakse. console.log('Cleanup ran') käivitub siis, kui komponent eemaldatakse.

Levinud stsenaariumid, mis nõuavad efekti puhastamist

Uurime mõningaid levinud stsenaariume, kus efekti puhastamine on ülioluline:

1. Taimerid (setTimeout ja setInterval)

Kui kasutate oma useEffect hookis taimereid, on oluline need tühistada, kui komponent eemaldatakse. Vastasel juhul jätkavad taimerid tööd ka pärast komponendi kadumist, põhjustades mälulekkeid ja potentsiaalselt vigu. Näiteks kujutage ette automaatselt uuenevat valuutamuundurit, mis hangib vahetuskursse teatud intervallide järel:


import React, { useState, useEffect } from 'react';

function CurrencyConverter() {
  const [exchangeRate, setExchangeRate] = useState(0);

  useEffect(() => {
    const intervalId = setInterval(() => {
      // Simuleerib vahetuskursi pärimist API-st
      const newRate = Math.random() * 1.2;  // Näide: Juhuslik kurss vahemikus 0 ja 1.2
      setExchangeRate(newRate);
    }, 2000); // Uuenda iga 2 sekundi järel

    return () => {
      clearInterval(intervalId);
      console.log('Interval cleared!');
    };
  }, []);

  return (
    

Current Exchange Rate: {exchangeRate.toFixed(2)}

); } export default CurrencyConverter;

Selles näites kasutatakse setInterval funktsiooni exchangeRate'i uuendamiseks iga 2 sekundi järel. Puhastusfunktsioon kasutab clearInterval intervalli peatamiseks, kui komponent eemaldatakse, vältides taimeri edasist töötamist ja mälulekke tekkimist.

2. Sündmuste kuulajad

Kui lisate oma useEffect hookis sündmuste kuulajaid, peate need eemaldama, kui komponent eemaldatakse. Selle tegemata jätmine võib põhjustada mitme sündmuste kuulaja lisamist samale elemendile, mis toob kaasa ootamatu käitumise ja mälulekkeid. Näiteks kujutage ette komponenti, mis kuulab akna suuruse muutmise sündmusi, et kohandada oma paigutust erinevate ekraanisuuruste jaoks:


import React, { useState, useEffect } from 'react';

function ResponsiveComponent() {
  const [windowWidth, setWindowWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => {
      setWindowWidth(window.innerWidth);
    };

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
      console.log('Event listener removed!');
    };
  }, []);

  return (
    

Window Width: {windowWidth}

); } export default ResponsiveComponent;

See kood lisab aknale resize sündmuse kuulaja. Puhastusfunktsioon kasutab removeEventListener kuulaja eemaldamiseks, kui komponent eemaldatakse, vältides mälulekkeid.

3. Tellimused (veebipesad, RxJS Observable'id jne)

Kui teie komponent tellib andmevoo, kasutades veebipesasid, RxJS Observable'eid või muid tellimismehhanisme, on ülioluline tellimusest loobuda, kui komponent eemaldatakse. Aktiivsete tellimuste jätmine võib põhjustada mälulekkeid ja tarbetut võrguliiklust. Vaatleme näidet, kus komponent tellib veebipesa voo reaalajas aktsiahindade saamiseks:


import React, { useState, useEffect } from 'react';

function StockTicker() {
  const [stockPrice, setStockPrice] = useState(0);
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    // Simuleerib WebSocketi ühenduse loomist
    const newSocket = new WebSocket('wss://example.com/stock-feed');
    setSocket(newSocket);

    newSocket.onopen = () => {
      console.log('WebSocket connected');
    };

    newSocket.onmessage = (event) => {
      // Simuleerib aktsiahinna andmete saamist
      const price = parseFloat(event.data);
      setStockPrice(price);
    };

    newSocket.onclose = () => {
      console.log('WebSocket disconnected');
    };

    newSocket.onerror = (error) => {
      console.error('WebSocket error:', error);
    };

    return () => {
      newSocket.close();
      console.log('WebSocket closed!');
    };
  }, []);

  return (
    

Stock Price: {stockPrice}

); } export default StockTicker;

Selle stsenaariumi korral loob komponent WebSocketi ühenduse aktsiate vooga. Puhastusfunktsioon kasutab socket.close() ühenduse sulgemiseks, kui komponent eemaldatakse, vältides ühenduse aktiivseks jäämist ja mälulekke tekkimist.

4. Andmete pärimine AbortControlleriga

Kui pärite andmeid useEffect'is, eriti API-dest, mille vastamine võib aega võtta, peaksite kasutama AbortController'it päringu tühistamiseks, kui komponent eemaldatakse enne päringu lõpulejõudmist. See väldib tarbetut võrguliiklust ja potentsiaalseid vigu, mis on põhjustatud komponendi oleku uuendamisest pärast selle eemaldamist. Siin on näide kasutajaandmete pärimisest:


import React, { useState, useEffect } from 'react';

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/user', { signal });
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const data = await response.json();
        setUser(data);
      } catch (err) {
        if (err.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      controller.abort();
      console.log('Fetch aborted!');
    };
  }, []);

  if (loading) {
    return 

Loading...

; } if (error) { return

Error: {error.message}

; } return (

User Profile

Name: {user.name}

Email: {user.email}

); } export default UserProfile;

See kood kasutab AbortController'it päringu tühistamiseks, kui komponent eemaldatakse enne andmete kättesaamist. Puhastusfunktsioon kutsub välja controller.abort() päringu tühistamiseks.

Sõltuvuste mõistmine useEffect'is

Sõltuvuste massiiv useEffect'is mängib olulist rolli määramisel, millal efekti uuesti käivitatakse. See mõjutab ka puhastusfunktsiooni. On oluline mõista, kuidas sõltuvused töötavad, et vältida ootamatut käitumist ja tagada korralik puhastus.

Tühi sõltuvuste massiiv ([])

Kui annate ette tühja sõltuvuste massiivi ([]), käivitub efekt ainult üks kord pärast esialgset renderdamist. Puhastusfunktsioon käivitub ainult siis, kui komponent eemaldatakse. See on kasulik kõrvalmõjude jaoks, mis tuleb seadistada ainult üks kord, näiteks veebipesa ühenduse lähtestamine või globaalse sündmuste kuulaja lisamine.

Väärtustega sõltuvused

Kui annate ette väärtustega sõltuvuste massiivi, käivitatakse efekt uuesti, kui mõni massiivi väärtus muutub. Puhastusfunktsioon käivitatakse *enne* efekti uuesti käivitamist, võimaldades teil puhastada eelmine efekt enne uue seadistamist. See on oluline kõrvalmõjude jaoks, mis sõltuvad konkreetsetest väärtustest, näiteks andmete pärimine kasutaja ID alusel või DOM-i uuendamine komponendi oleku põhjal.

Vaatleme seda näidet:


import React, { useState, useEffect } from 'react';

function DataFetcher({ userId }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    let didCancel = false;

    const fetchData = async () => {
      try {
        const response = await fetch(`https://api.example.com/users/${userId}`);
        const result = await response.json();
        if (!didCancel) {
          setData(result);
        }
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();

    return () => {
      didCancel = true;
      console.log('Fetch cancelled!');
    };
  }, [userId]);

  return (
    
{data ?

User Data: {data.name}

:

Loading...

}
); } export default DataFetcher;

Selles näites sõltub efekt userId prop'ist. Efekti käivitatakse uuesti, kui userId muutub. Puhastusfunktsioon seab didCancel lipu väärtuseks true, mis takistab oleku uuendamist, kui päring lõpeb pärast komponendi eemaldamist või userId muutumist. See hoiab ära hoiatuse "Can't perform a React state update on an unmounted component".

Sõltuvuste massiivi ära jätmine (kasutage ettevaatlikult)

Kui jätate sõltuvuste massiivi ära, käivitub efekt pärast iga renderdamist. See on üldiselt ebasoovitav, kuna see võib põhjustada jõudlusprobleeme ja lõputuid tsükleid. Siiski on mõned harvad juhud, kus see võib olla vajalik, näiteks kui peate efektis pääsema juurde prop'ide või oleku viimastele väärtustele, ilma neid sõltuvustena selgesõnaliselt loetlemata.

Tähtis: Kui jätate sõltuvuste massiivi ära, peate olema *äärmiselt* ettevaatlik kõrvalmõjude puhastamisel. Puhastusfunktsioon käivitatakse enne *iga* renderdamist, mis võib olla ebaefektiivne ja potentsiaalselt probleeme tekitada, kui seda õigesti ei käsitleta.

Efekti puhastamise parimad tavad

Siin on mõned parimad tavad, mida efekti puhastamisel järgida:

Tööriistad mälulekete tuvastamiseks

Mitmed tööriistad aitavad teil Reacti rakendustes mälulekkeid tuvastada:

Kokkuvõte

Reacti efekti puhastamise valdamine on oluline vastupidavate, jõudluspõhiste ja mäluefektiivsete Reacti rakenduste ehitamiseks. Mõistes efekti puhastamise põhimõtteid ja järgides selles juhendis toodud parimaid tavasid, saate vältida mälulekkeid ja tagada sujuva kasutajakogemuse. Pidage meeles, et alati tuleb puhastada kõrvalmõjud, olla tähelepanelik sõltuvuste suhtes ja kasutada olemasolevaid tööriistu võimalike mälulekete tuvastamiseks ja lahendamiseks oma koodis.

Neid tehnikaid hoolikalt rakendades saate tõsta oma Reacti arendusoskusi ja luua rakendusi, mis pole mitte ainult funktsionaalsed, vaid ka jõudluspõhised ja usaldusväärsed, aidates kaasa paremale üldisele kasutajakogemusele kasutajate jaoks üle maailma. See ennetav lähenemine mäluhaldusele eristab kogenud arendajaid ja tagab teie Reacti projektide pikaajalise hooldatavuse ja skaleeritavuse.