Kā pareizi lietot useEffect un useState pakalpojumā React

Pēdējā atjaunošana: 02/12/2026
  • Izprast, kā useState saglabā un atjaunina lokālo komponentu stāvokli, tostarp funkcionālos atjauninājumus un objektu apstrādi.
  • Izmantojiet useEffect blakusefektiem ar skaidru iestatīšanas/tīrīšanas loģiku un precīziem atkarību masīviem, lai izvairītos no noplūdēm un cilpām.
  • Apvienojiet useState un useEffect reāliem uzdevumiem, piemēram, datu izgūšanai, abonēšanai un DOM atjauninājumiem funkciju komponentos.
  • Ievērojiet āķu noteikumus un apstrādājiet efektus kā "pēc renderēšanas" procesus, lai React komponenti būtu paredzami un uzturami.

React āķi useState un useEffect

React āķi pilnībā mainīja komponentu rakstīšanas veidu, un apgūšana useState un useEffect būtībā ir ieejas biļete mūsdienīga React koda rakstīšanai. Ja jūs tos jau izmantojat, bet joprojām saskaraties ar bezgalīgām cilpām, novecojušiem stāvokļiem vai mulsinošiem atkarību masīviem, šī rokasgrāmata palīdzēs jums praktiski savienot visas trūkstošās daļas.

Šajā rakstā mēs sīkāk aplūkosim, kā pareizi lietot useState un useEffect kopā, kāpēc vispār tika ieviesti āķi, oficiālie noteikumi un brīdinājumi, kā atkarības patiesībā darbojas zem pārsega, bieži sastopamās kļūmes, kas sagrauj jūsu komponentus, un kaujas gaitā pārbaudītas blakusparādību, tīrīšanas un stāvokļa pārvaldības shēmas reālos projektos.

Kāpēc izmantot āķus un kāpēc tieši useState un useEffect?

React 16.8 versijā tika pievienoti āķi, lai funkciju komponenti varētu izmantot stāvokļa un dzīves cikla funkcijas bez klasēmPirms tam bija jāraksta klases komponenti, lai saglabātu lokālo stāvokli, abonētu ārējos datus vai reaģētu uz dzīves cikla notikumiem, piemēram, pievienošanu un atvienošanu.

Lielākā problēma ar klasēm bija tā, ka saistītā loģika bieži tika sadalīta vairākās dzīves cikla metodēs. piemēram, componentDidMount, componentDidUpdate un componentWillUnmountJūs nonāktu pie vienas un tās pašas funkcijas fragmentiem, kas izkaisīti pa dažādām metodēm, pamatojoties uz kad viņi skrien tā vietā, ko tā notiek, kas apgrūtina koda lasīšanu, testēšanu un atkārtotu izmantošanu.

Āķi apgriež šo modeli otrādi: ar useState jūs pievienojat stāvokli tieši funkcijas komponentam un ar useEffect Jūs pievienojat blakusparādības tieši loģikai, kurai tās nepieciešamas. Tādā veidā jūs varat visu, kas saistīts ar vienu problēmu, grupēt vienuviet un vēlāk viegli iegūt atkārtoti izmantojamus āķus.

Starp visiem āķiem, useState un useEffect ir galvenie primitīviLielāko daļu ikdienas funkciju var izveidot, izmantojot tikai šīs divas funkcijas: lietotāja interfeisa stāvokļa iestatījumus, piemēram, veidlapas un pārslēgšanas pogas, tīkla pieprasījumus, abonementus, taimerus, DOM atjauninājumus un citas. Citi āķi (useRef, useReducer, useContext, useMemo...) ir lieliski, bet tie balstās uz tām pašām idejām.

React āķu noteikumi, kurus nekad nedrīkst pārkāpt

React āķiem ir pāris stingri noteikumi, kas nodrošina to uzticamu darbību dažādos renderējumos.Ja tos pārkāpsiet, jūs redzēsiet vai nu izpildlaika kļūdas, vai arī ļoti smalkas, grūti atkļūdojamas kļūdas.

Pirmais noteikums: izsauciet āķus tikai React funkciju komponentu vai pielāgotu āķu iekšpusēJūs nevarat izmantot useState or useEffect klases komponentos, regulārās lietderības funkcijās vai ārpus jebkura komponenta. Šāds modelis nav derīgs:

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

class App extends Component {
  // ❌ This will throw - hooks don’t work in classes
  const  = useState(0);
  render() {
    return <h1>Hello, I am a Class Component!</h1>;
  }
}

Pareizā pieeja ir pāriet uz funkcijas komponentu, ja vēlaties izmantot āķus.:

import React, { useState } from 'react';

function App() {
  const  = useState('');

  return (
    <div>
      Your JSX code goes in here...
    </div>
  );
}

export default App;

Otrais noteikums: izsauciet āķus tikai komponentes augšējā līmenīTas nozīmē, ka cilpās, nosacījumos vai ligzdotās funkcijās nav āķu. React paļaujas uz āķu izsaukšanu vienā un tajā pašā secībā katrā renderēšanā, lai "saskaņotu" katru. useState un useEffect izsaukums ar tā saglabātajiem datiem, tāpēc šis nav derīgs:

function BadComponent({ enabled }) {
  if (enabled) {
    // ❌ Wrong: hook inside a conditional
    const  = useState(0);
  }
  // ...
}

Tā vietā deklarējiet āķus bez nosacījumiem augšpusē un izmantojiet nosacījumus efekta vai JSX iekšpusē.Āķis vienmēr ir jāizsauc, bet tā izpildāmā loģika var būt nosacīta:

function ConditionalEffectComponent() {
  const  = useState(false);

  useEffect(() => {
    if (isMounted) {
      console.log('Component mounted');
    }
  }, );

  return (
    <div>
      <button onClick={() => setIsMounted(!isMounted)}>
        {isMounted ? 'Unmount' : 'Mount'}
      </button>
    </div>
  );
}

Trešais netiešais noteikums ir tāds, ka āķi ir jāimportē no React (vai āķu bibliotēkas), nevis jāievieš ad-hoc.Tas ir acīmredzams, taču ir vērts pieminēt: maģija slēpjas React iekšējā āķu dispečerā, kas izseko āķu izsaukumus visā renderēšanas laikā.

Pareiza lokālā stāvokļa pārvaldība, izmantojot useState

useState ļauj pievienot stāvokli funkcijas komponentam un saņemt gan pašreizējo vērtību, gan atjauninātāja funkcijuKonceptuāli tas ir funkcionāls analogs this.state un this.setState klases sastāvdaļās.

Minimāls pretpiemērs ar useState izskatās šādi:

import React, { useState } from 'react';

function Counter() {
  const  = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Counter;

Kad tu zvani useState(initialValue)React saglabā šo stāvokli un atgriež pāri: pašreizējā stāvokļa vērtība un setter. Atšķirībā no parastajiem lokālajiem mainīgajiem, stāvoklis saglabājas visā renderēšanas laikā, tāpēc count vērtība netiek atiestatīta uz 0 katru reizi, kad tiek palaista komponentes funkcija.

Stāvoklim var izmantot jebkuru serializējamu vērtību: skaitļus, virknes, Būla vērtības, masīvus, objektus un pat funkcijas.. Var arī piezvanīt useState vairākas reizes vienā un tajā pašā komponentā, lai saistītās vērtības saglabātu atsevišķi, nevis visu ievietotu vienā objektā.

Ja jaunā stāvokļa vērtība ir atkarīga no iepriekšējās, vienmēr izmantojiet funkcionālās atjaunināšanas veidlapu.Tas novērš kļūdas, ja vairāki stāvokļa atjauninājumi notiek ātri pēc kārtas:

setCount(prev => prev + 1);

Vēl viena smalka, bet svarīga detaļa ir tā, ka setera izsaukšana aizstāj visu stāvokļa vērtību, tā neapvieno objektus, piemēram, this.setState nodarbībāsJa jūsu stāvoklis ir objekts vai masīvs, jums pašam ir jāizplata iepriekšējā vērtība:

const  = useState({ name: 'Alex', age: 30 });

// ✅ Correct: copy and update
setUser(prev => ({ ...prev, age: prev.age + 1 }));

Dārgām sākotnējām vērtībām stāvokli var inicializēt slinki, nododot funkciju useStateReact to izsauks tikai pirmajā renderēšanas reizē:

const  = useState(() => calculateInitialValue());

Blakusparādību ārstēšana, lietojot useEffect

useEffect ir React API blakusefektu palaišanai funkciju komponentos“Blakusefekts” ir jebkas, kas skar ārpasauli: datu izgūšana, reģistrēšana, tiešas DOM izmaiņas, abonementi, taimeri, pārlūkprogrammas API utt.

Konceptuāli, useEffect aizstāj kombināciju no componentDidMount, componentDidUpdate un componentWillUnmount no klases komponentiemTā vietā, lai sadalītu vienu efektu trīs dzīves cikla metodēs, jūs to deklarējat vienreiz un ļaujat React apstrādāt tā palaišanas un tīrīšanas procesus.

Pamata paraksts ir useEffect(setup, dependencies?). setup funkcija ir jūsu efekta pamatteksts; tā var pēc izvēles atgriezt tīrīšanas funkciju. dependencies Masīvs norāda React, kad efekts ir jāizpilda atkārtoti.

useEffect(() => {
  // side effect logic here

  return () => {
    // optional cleanup logic here
  };
}, );

Pēc noklusējuma, bez otrā argumenta, efekts tiks palaists pēc katras renderēšanas. (pirmais pieslēgums un katrs nākamais atjauninājums). Tas bieži vien ir par daudz tīkla pieprasījumiem vai dārgai loģikai.

Ļoti izplatīta tendence ir atjaunināt kaut ko ārēju ikreiz, kad mainās kāda stāvokļa daļa.Piemēram, lapas nosaukuma atjaunināšana atkarībā no klikšķu skaita:

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

function Counter() {
  const  = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, ); // effect re-runs only when `count` changes

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

Atkarību masīvs ir ļoti svarīgs veiktspējai un pareizībaiTas kontrolē, kad React atkārtoti jāpalaiž efekts: vai kāda atkarība ir mainījusies atbilstoši Object.is Salīdzinājumā efekts tiek attīrīts un palaists vēlreiz; ja nekas nemainās, tas tiek izlaists.

Izprotiet atkarību masīvu kā profesionālis

Atkarību masīvs ir visneuzkrītošākais useEffect kļūdas rodas noReact salīdzina katru masīva elementu ar tā iepriekšējo vērtību, izmantojot Object.isJa visas vērtības ir vienādas, efekts tiek izlaists; ja vismaz viena ir atšķirīga, efekts tiek izpildīts atkārtoti.

Ir trīs galvenās atkarību konfigurācijas, kuras izmantosiet visu laiku:

  • Nav otrā argumenta: efekts darbojas pēc katras renderēšanas.
  • Tukšs masīvs []: efekts darbojas tikai vienreiz piestiprināšanas laikā un izzūd atvienošanas laikā.
  • Masīvs ar vērtībām : efekts darbojas pēc pievienošanas un ikreiz, kad mainās kāda atkarība.

Ja atkarības ir primitīvas vērtības (skaitļi, virknes, Būla vērtības), tas ir vienkāršiProblēmas sākas, ievietojot objektus, masīvus vai funkcijas atkarībās, jo vienādība ir balstīta uz atsaucēm. Divi identiski objekti ar atšķirīgām atsaucēm tiek uzskatīti par “atšķirīgiem”, kas izraisa atkārtotu palaišanu katrā renderēšanā.

Apsveriet efektu, kas ir atkarīgs no team objekts no butaforijām:

function Team({ team }) {
  useEffect(() => {
    console.log(team.id, team.active);
  }, ); // ⚠️ might re-run every render if `team` reference changes
}

Pat ja faktiskais komandas saturs nemainās, jauna objekta atsauce katrā renderēšanā piespiedīs efektu darboties vēlreiz.Lai no tā izvairītos, vai nu paļaujieties uz faktiski izmantotajiem primitīvajiem laukiem, vai arī rekonstruējiet objektu pašā efektā.

Drošāka versija izseko tikai to efektu, kas patiesībā ir nepieciešams:

function Team({ team }) {
  const { id, active } = team;

  useEffect(() => {
    console.log(id, active);
  }, );
}

Ja jums patiešām ir nepieciešams viss objekts efekta iekšpusē, varat to tur izveidot atkārtoti, nevis izmantot kā atkarību.Tādā veidā atkarību saraksts joprojām var būt balstīts uz primitīviem:

function Team({ team }) {
  const { id, active, name } = team;

  useEffect(() => {
    const localTeam = { id, active, name };
    // use `localTeam` here
  }, );
}

Kā pēdējo līdzekli varat izmantot atmiņu veidošanu ar useMemo or useCallback dārgiem priekšmetiem vai funkcijām, taču atcerieties, ka iegaumēšanai pašai par sevi ir sava cena. Neizkaisiet to visur “katram gadījumam”; pievienojiet to, kad konkrēta atkarība patiešām rada veiktspējas problēmas.

Pareiza efektu tīrīšana

Dažas blakusparādības piešķir resursus, kas ir jāatbrīvo: abonementi, ligzdas, intervāli, taimauti, notikumu klausītāji utt. To iztīrīšanas aizmirstība var viegli izraisīt atmiņas noplūdes vai dublētu darbu.

In useEffect, tīrīšana tiek veikta, atgriežot funkciju no efektaReact izsauks šo funkciju pirms efekta atkārtotas palaišanas ar jaunām atkarībām, kā arī pēdējo reizi, kad komponents tiks atvienots.

import { useEffect } from 'react';

function LogMessage({ message }) {
  useEffect(() => {
    const log = setInterval(() => {
      console.log(message);
    }, 1000);

    return () => {
      clearInterval(log);
    };
  }, );

  return <div>logging to console "{message}"</div>;
}

Šajā piemērā katru reizi message izmaiņas, React vispirms notīra veco intervālu un pēc tam iestata jaunu ar atjaunināto ziņojumuKad komponents pazūd no lietotāja saskarnes, pēdējā tīrīšanas darbība uz visiem laikiem notīra intervālu.

Šis “iestatīšanas + sakopšanas” apvienojums ir mentālā modeļa centrālais elements. useEffectCentieties katru efektu iztēloties kā patstāvīgu procesu, kas sākas iestatīšanas funkcijā un pilnībā apstājas tīrīšanas funkcijā. React izstrādes laikā (īpaši stingrajā režīmā) var palaist vairākus iestatīšanas/tīrīšanas ciklus, lai pārbaudītu, vai jūsu tīrīšana patiešām visu atceļ.

Klasisks piemērs ir abonēšana ārējam avotam, piemēram, tērzēšanas API vai pārlūkprogrammas notikumam (skatiet onKeyDown apstrāde React vidē):

useEffect(() => {
  function handleClick(event) {
    console.log('Clicked', event.clientX, event.clientY);
  }

  document.addEventListener('click', handleClick);

  return () => {
    document.removeEventListener('click', handleClick);
  };
}, []); // runs once on mount, cleans up on unmount

Izmantojot useState un useEffect kopā datu izgūšanai

Viena no visizplatītākajām kombinācijām reālajā pasaulē ir useState un useEffect lai izgūtu datus no APIJūs saglabājat datus (un, iespējams, ielādes/kļūdas karodziņus) stāvoklī un izpildāt pieprasījumu efektā, kas darbojas, kad komponents tiek pievienots vai mainās kāds parametrs.

Pamata datu izgūšanas modelis pēc pievienošanas izskatās šādi:

import { useEffect, useState } from 'react';

function FetchItems() {
  const  = useState([]);

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

    async function fetchItems() {
      try {
        const response = await fetch('/items');
        const fetchedItems = await response.json();
        if (!ignore) {
          setItems(fetchedItems);
        }
      } catch (error) {
        console.error('Error fetching items:', error);
      }
    }

    fetchItems();

    return () => {
      // avoid updating state if the component unmounted
      ignore = true;
    };
  }, []);

  return (
    <div>
      {items.map(item => (
        <div key={item.id ?? item}>{item.name ?? item}</div>
      ))}
    </div>
  );
}

Šeit tukšais atkarību masīvs nodrošina, ka pieprasījums tiek izpildīts tieši vienu reizi.Iekšējais ignore karodziņš ir vienkāršs veids, kā izvairīties no stāvokļa iestatīšanas neuzstādītam komponentam, ja pieprasījums tiek atrisināts vēlu.

Ir arī ļoti bieži pievienot ielādes karodziņu un rādīt ritinātāju vai vietturi, kamēr dati ir ceļā.:

const Statistics = () => {
  const  = useState([]);
  const  = useState(true);

  useEffect(() => {
    const getStats = async () => {
      try {
        const statsData = await getData();
        setStats(statsData);
      } finally {
        setLoading(false);
      }
    };

    getStats();
  }, []);

  if (loading) {
    return <div>Loading statistics...</div>;
  }

  return (
    <ul>
      {stats.map(stat => (
        <li key={stat.id}>{stat.label}: {stat.value}</li>
      ))}
    </ul>
  );
};

Ja jūsu vaicājums ir atkarīgs no parametra (piemēram, kategorijas, filtra vai maršruta parametra), pievienojiet šo parametru atkarību masīvam. tātad efekts atkārtojas, kad tas mainās:

useEffect(() => {
  async function fetchItems() {
    const response = await fetch(`/items?category=${category}`);
    const data = await response.json();
    setItems(data);
  }

  fetchItems();
}, );

Domājot par “efektiem katrā renderējumā” salīdzinājumā ar “dzīves cikliem”

Ja esat pieradis pie klases komponentiem, var rasties kārdinājums mentāli kartēt useEffect lai pievienotu/atjauninātu/atvienotu metodes, bet tas parasti rada vēl lielāku apjukumu. Vienkāršāks mentālais modelis ir: “efekti darbojas pēc renderēšanas un var tikt sakārtoti pirms nākamās palaišanas”.

Nodarbībās bieži nācās dublēt loģiku starp componentDidMount un componentDidUpdate jo jūs vēlējāties, lai viens un tas pats efekts darbotos gan piestiprināšanas, gan atjaunināšanas laikā. Ar āķiem šī dublēšanās izzūd: viens efekts aptver abus gadījumus, un React rūpējas par tīrīšanu starp izpildes reizēm.

Šis dizains arī novērš veselu kļūdu klasi, kas saistīta ar nepareizu atjauninājumu apstrādi.Piemēram, klases komponentā, kas abonē drauga tiešsaistes statusu, ir viegli aizmirst atkārtoti abonēt, kad props.friend izmaiņas, kas izraisa novecojušus abonementus vai avārijas atvienošanas laikā. Ar useEffect kas uzskaita friend.id kā atkarība, React automātiski veiks vecā drauga tīrīšanu un jaunā drauga iestatīšanu.

Paturiet prātā, ka izstrādes laikā Strict režīmā React apzināti divreiz palaiž iestatīšanas + tīrīšanas ciklu, kad tas tiek pievienots.Tas nenotiek ražošanas vidē, taču tas ir noderīgs stresa tests, lai apstiprinātu, ka jūsu tīrīšana patiešām visu atceļ un ka jūsu efektu var droši palaist vairākas reizes.

Optimizācija un problēmu novēršana useEffect uzvedībā

Ja efekts darbojas biežāk nekā paredzēts, vispirms jāpārbauda atkarību masīvs.Vai nu atkarība mainās katrā renderēšanas reizē (kas bieži notiek ar iekļautiem objektiem/funkcijām), vai arī masīvs vispār ir aizmirsts norādīt.

Atkarību vērtību reģistrēšana ir ātrs veids, kā atkļūdot:

useEffect(() => {
  console.log('Effect deps:', dep1, dep2);
}, );

Ja katru reizi redzat atšķirīgus žurnālus, pārbaudiet, kura atkarība faktiski mainās.Bieži vien katrā renderēšanā var atkārtoti izveidot iekļautu objektu vai bultiņas funkciju. Pārvietojot objekta izveidi efekta ietvaros, atceļot funkcijas ārpus komponentes vai saglabājot tās atmiņā ar useCallback var stabilizēt atkarības, kad tas nepieciešams.

Bezgalīgas cilpas rodas, ja efekts ir atkarīgs no vērtības un bez nosacījumiem atjaunina to pašu vērtību.. Piemēram:

useEffect(() => {
  setCount(count + 1); // ⚠️ will cause a loop if `count` is a dependency
}, );

Katru reizi count izmaiņas, efekts darbojas, atjauninājumi count atkal aktivizē citu renderēšanu utt.Lai pārtrauktu šo modeli, apsveriet, vai stāvokļa atjauninājums patiešām pieder efektam, vai tam vajadzētu būt aktivizētam ar lietotāja mijiedarbību, vai arī varat paļauties uz citu vērtību.

Dažreiz ir nepieciešams nolasīt kāda stāvokļa vai rekvizītu jaunāko vērtību efekta ietvaros, neizraisot atkārtotu izpildi.Šajos uzlabotajos scenārijos jaunākas API, piemēram, “efekta notikumi” (izmantojot useEffectEvent React dokumentācijā) vai atsauces var palīdzēt, taču praktiskos gadījumos drošāk un vienkāršāk ir saglabāt uzticību atkarībām.

Saliekot visu kopā, izmantojot useState un useEffect pareizi reducējas uz dažiem pamata ieradumiem: saglabājiet stāvokli mazu un fokusētu, dodiet priekšroku funkcionāliem atjauninājumiem, atvasinot jaunu stāvokli no vecā, strukturējiet efektus ap iestatīšanas/tīrīšanas pāriem, esiet godīgi un skaidri ar atkarību masīviem un vienmēr ievērojiet āķu noteikumus, lai React varētu droši izsekot, kas kur pieder. Ievērojot šos principus, jūsu komponenti paliek paredzami, jūsu blakusparādības uzvedas atbilstoši un jūsu React koda bāze kļūst daudz vieglāk attīstāma, lietotnei augot.

saistīto rakstu:
Atrisināts: Kā uzstādīt react native āķus ar
Related posts: