Paano Gamitin nang Tama ang useEffect at useState sa React

Huling pag-update: 02/12/2026
May-akda: C SourceTrail
  • Unawain kung paano pinapanatili at ina-update ng useState ang lokal na estado ng bahagi, kabilang ang mga functional update at object handling.
  • Gamitin ang useEffect para sa mga side effect na may malinaw na setup/cleanup logic at tumpak na dependency arrays upang maiwasan ang mga leak at loop.
  • Pagsamahin ang useState at useEffect para sa mga totoong gawain tulad ng pagkuha ng data, mga subscription at mga update ng DOM sa mga bahagi ng function.
  • Sundin ang mga tuntunin ng hooks at ituring ang mga effect bilang mga prosesong "after render" upang mapanatiling mahuhulaan at mapanatili ang mga bahagi ng React.

Mga kawit ng reaksyon na useState at useEffect

Ganap na binago ng mga React hook kung paano tayo nagsusulat ng mga component, at mastering useState at useEffect ay karaniwang ang entry ticket sa pagsulat ng modernong React code. Kung ginagamit mo na ang mga ito ngunit natigil pa rin sa mga infinite loop, stale state, o nakakalitong dependency arrays, tutulungan ka ng gabay na ito na ikonekta ang lahat ng nawawalang piraso sa isang praktikal na paraan.

Sa artikulong ito, tatalakayin natin nang mas malalim kung paano gamitin nang tama ang useState at useEffect magkasama, kung bakit ipinakilala ang mga hook sa simula pa lang, ang mga opisyal na tuntunin at mga babala, kung paano talaga gumagana ang mga dependency sa likod, mga karaniwang patibong na sumisira sa iyong mga bahagi, at mga pattern na nasubukan na para sa mga side effect, paglilinis at pamamahala ng estado sa mga totoong proyekto.

Bakit hooks, at bakit partikular na useState at useEffect?

Idinagdag ang mga hook sa React 16.8 upang hayaan ang mga function component na gumamit ng mga state at lifecycle feature nang walang mga klase.Bago iyon, kinailangan mong magsulat ng mga component ng klase upang mapanatili ang lokal na estado, mag-subscribe sa panlabas na data, o tumugon sa mga kaganapan sa lifecycle tulad ng pag-mount at pag-unmount.

Ang malaking problema sa mga klase ay ang kaugnay na lohika ay kadalasang nahahati sa maraming pamamaraan ng lifecycle. tulad ng componentDidMount, componentDidUpdate at componentWillUnmountMagkakaroon ka ng mga piraso ng parehong tampok na nakakalat sa iba't ibang mga pamamaraan batay sa kailan tumatakbo sila sa halip na Ano ginagawa nga nila, na nagpapahirap basahin, subukan, at gamitin muli ang code.

Pinapaikot ng mga kawit ang modelong ito: kasama useState direktang ikinakabit mo ang estado sa isang bahagi ng function, at kasama ang useEffect Direktang inilalagay mo ang mga side effect sa lohikang nangangailangan ng mga ito. Sa ganoong paraan, maaari mong pangkatin ang lahat ng bagay na may kaugnayan sa iisang alalahanin sa isang lugar at madaling makuha ang mga magagamit muli na kawit sa ibang pagkakataon.

Sa lahat ng mga kawit, useState at useEffect ay ang mga pangunahing primitiboMaaari kang bumuo ng halos lahat ng pang-araw-araw na feature gamit lamang ang dalawang ito: mga UI state tulad ng mga form at toggle, mga kahilingan sa network, mga subscription, mga timer, mga update sa DOM at marami pang iba. Iba pang mga hook (useRef, useReducer, useContext, useMemo...) ay magagaling, ngunit binubuo nila ang parehong mga ideya.

Mga Panuntunan ng React hooks na hindi mo dapat sirain

Ang mga React hook ay may kasamang ilang mahigpit na patakaran na nagpapagana sa mga ito nang maaasahan sa iba't ibang render.Kung lalabagin mo ang mga ito, makakakita ka ng mga runtime error o mga napakaliit at mahirap i-debug na bug.

Unang tuntunin: tawagin lamang ang mga hook sa loob ng mga bahagi ng function ng React o mga custom na hookHindi mo maaaring gamitin useState or useEffect sa mga component ng klase, mga regular na utility function, o sa labas ng anumang component. Ang pattern na tulad nito ay hindi wasto:

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>;
  }
}

Ang tamang paraan ay ang lumipat sa isang function component kung gusto mong gumamit ng mga hook:

import React, { useState } from 'react';

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

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

export default App;

Pangalawang tuntunin: tawagin lamang ang mga hook sa pinakamataas na antas ng iyong componentIbig sabihin, walang mga hook sa loob ng mga loop, condition, o nested function. Ang React ay umaasa sa pagtawag ng mga hook sa parehong pagkakasunud-sunod sa bawat render upang "magtugma" ang bawat isa. useState at useEffect tumawag gamit ang nakaimbak na data nito, kaya hindi ito wasto:

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

Sa halip, ideklara ang mga hook nang walang kondisyon sa itaas at gumamit ng mga conditional sa loob ng effect o JSXAng hook ay dapat palaging tawagin, ngunit ang lohika na pinapatakbo nito ay maaaring maging kondisyonal:

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

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

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

Ang ikatlong ipinahiwatig na tuntunin ay ang mga hook ay dapat i-import mula sa React (o isang hook library), hindi ipinapatupad nang ad-hoc.. Malinaw ito, ngunit mahalagang sabihin: ang mahika ay nasa internal hook dispatcher ng React na sumusubaybay sa mga hook call sa mga render.

Pamamahala nang tama ng lokal na estado gamit ang useState

useState hinahayaan kang ilakip ang estado sa isang bahagi ng function at matanggap ang parehong kasalukuyang halaga at isang function ng updaterSa konseptwal na aspeto, ito ang katumbas na gumagana ng this.state at this.setState sa mga bahagi ng klase.

Isang minimal na halimbawa ng kontra na may useState ganito ang hitsura nito:

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;

Kapag tumawag ka useState(initialValue), Iniimbak ng React na nagsasaad at nagbabalik ng isang pares: ang kasalukuyang halaga ng estado at isang setter. Hindi tulad ng mga normal na lokal na baryabol, ang estado ay nananatili sa iba't ibang render, kaya ang count Ang halaga ay hindi nagre-reset sa 0 sa bawat oras na tumatakbo ang component function.

Maaari kang gumamit ng anumang serializable value para sa state: mga numero, string, boolean, array, object at maging mga function. Maaari ka ring tumawag useState nang maraming beses sa parehong component upang mapanatiling hiwalay ang mga kaugnay na value sa halip na pagdikitin ang lahat sa iisang object.

Kapag ang bagong halaga ng estado ay nakadepende sa nauna, palaging gamitin ang functional update form. Naiiwasan nito ang mga bug kapag ang maraming pag-update ng estado ay nangyayari nang mabilis at sunod-sunod:

setCount(prev => prev + 1);

Isa pang banayad ngunit mahalagang detalye ay ang pagtawag sa setter ay pinapalitan ang buong halaga ng estado, hindi nito pinagsasama ang mga bagay tulad ng this.setState sa mga klaseKung ang iyong estado ay isang object o isang array, kailangan mong ikalat ang nakaraang value nang mag-isa:

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

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

Para sa mga mamahaling paunang halaga, maaari mong i-lazy-initialize ang estado sa pamamagitan ng pagpasa ng isang function sa useStateTatawagin lamang ito ng React sa unang render:

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

Paghawak sa mga side effect gamit ang Epekto

useEffect ay ang API ng React para sa pagpapatakbo ng mga side effect sa mga function componentAng isang "side effect" ay anumang bagay na nakakaapekto sa labas ng mundo: pagkuha ng data, pag-log, direktang pagbabago sa DOM, mga subscription, mga timer, mga browser API, atbp.

Konseptwal, useEffect pinapalitan ang kombinasyon ng componentDidMount, componentDidUpdate at componentWillUnmount mula sa mga bahagi ng klaseSa halip na hatiin ang isang effect sa tatlong lifecycle methods, idinedeklara mo ito nang isang beses at hahayaan mong ang React ang humawak kung kailan ito tumatakbo at kung kailan ito naglilinis.

Ang pangunahing lagda ay useEffect(setup, dependencies?). ang setup ang function ay ang iyong effect body; maaari itong opsyonal na magbalik ng cleanup function. Ang dependencies Sinasabi ng array sa React kung kailan kailangang patakbuhin muli ang effect.

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

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

Bilang default, kung wala ang pangalawang argumento, ang epekto ay tatakbo pagkatapos ng bawat render (unang pag-mount at bawat kasunod na update). Kadalasan ay sobra na iyon para sa mga kahilingan sa network o magastos na lohika.

Isang karaniwang padron ang pag-update ng isang bagay na panlabas tuwing nagbabago ang isang bahagi ng estado.Halimbawa, ang pag-update ng pamagat ng pahina depende sa bilang ng mga pag-click:

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>
  );
}

Ang dependency array ay mahalaga para sa pagganap at kawastuhanKinokontrol nito kung kailan dapat muling patakbuhin ng React ang effect: kung may anumang dependency na nagbago ayon sa Object.is Sa paghahambing, ang epekto ay nililinis at tumatakbo muli; kung walang nagbago, ito ay nilalaktawan.

Pag-unawa sa dependency array tulad ng isang propesyonal

Ang dependency array ang pinakabanayad useEffect mga insekto ay nagmumula saInihahambing ng React ang bawat elemento ng array sa nakaraang halaga nito gamit ang Object.isKung pantay-pantay ang lahat ng halaga, nilalaktawan ang epekto; kung kahit isa lang ang magkaiba, muling isinasagawa ang epekto.

May tatlong pangunahing configuration ng dependency na gagamitin mo sa lahat ng oras:

  • Walang pangalawang argumento: ang epekto ay tumatakbo pagkatapos ng bawat render.
  • Walang laman na hanay []: ang epekto ay gumagana nang isang beses lamang sa pag-mount at nalilinis kapag na-unmount.
  • Array na may mga halaga : ang epekto ay tumatakbo pagkatapos ng mount at tuwing magbabago ang anumang dependency.

Kapag ang mga dependency ay mga primitive na halaga (mga numero, string, boolean), ito ay diretsoNagsisimula ang mga problema kapag naglagay ka ng mga object, array, o function sa loob ng mga dependency, dahil ang equality ay nakabatay sa reference. Ang dalawang magkaparehong object na may magkaibang reference ay itinuturing na "magkakaiba", na nagiging sanhi ng mga re-run sa bawat render.

Isaalang-alang ang isang epekto na nakadepende sa isang team bagay mula sa mga props:

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

Kahit na hindi magbago ang aktwal na nilalaman ng koponan, ang isang bagong sanggunian ng bagay sa bawat render ay pipiliting gumana muli ang epekto.Para maiwasan ito, umasa sa mga primitive field na aktwal mong ginagamit, o muling buuin ang object sa loob mismo ng effect.

Sinusubaybayan lamang ng mas ligtas na bersyon kung ano talaga ang kailangan ng epekto:

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

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

Kung talagang kailangan mo ang buong bagay sa loob ng epekto, maaari mo itong muling likhain doon sa halip na gamitin ito bilang isang dependency.Sa ganoong paraan, ang listahan ng dependency ay maaari pa ring ibatay sa mga primitibo:

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

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

Bilang huling paraan, maaari mong gamitin ang memoization gamit ang useMemo or useCallback para sa mga mamahaling bagay o tungkulin, ngunit tandaan na ang memoization mismo ay may kapalit. Huwag itong ikalat kahit saan "kung sakali"; idagdag ito kapag ang isang partikular na dependency ay talagang nagdudulot ng mga isyu sa pagganap.

Nililinis nang tama ang mga epekto

Ang ilang mga side effect ay naglalaan ng mga mapagkukunan na dapat ilabas: mga subscription, socket, interval, timeout, event listener, atbp. Ang pagkalimot na linisin ang mga ito ay madaling humantong sa mga memory leak o duplicate na gawain.

In useEffect, ang paglilinis ay hinahawakan sa pamamagitan ng pagbabalik ng isang function mula sa effectTatawagin ng React ang function na ito bago patakbuhin muli ang effect gamit ang mga bagong dependency, at sa huling pagkakataon din kapag nag-unmount ang component.

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>;
}

Sa halimbawang ito, sa bawat pagkakataon message mga pagbabago, unang nililimas ng React ang lumang interval, pagkatapos ay nagse-set up ng bago gamit ang na-update na mensaheKapag nawala ang component sa UI, tuluyan nang nililimas ang interval sa huling paglilinis.

Ang pagpapares na ito ng "setup + cleanup" ay mahalaga sa mental na modelo ng useEffectSubukang isipin ang bawat effect bilang isang prosesong nagsasarili na nagsisimula sa setup function at tuluyang humihinto sa cleanup function. Maaaring magpatakbo ang React ng maraming setup/cleanup cycle na nasa proseso ng pag-develop (lalo na sa ilalim ng Strict Mode) para ma-stress test kung talagang naa-undo ng iyong cleanup ang lahat.

Isang klasikong halimbawa ay ang pag-subscribe sa isang panlabas na mapagkukunan, tulad ng isang chat API o kaganapan sa browser (tingnan ang paghawak sa onKeyDown sa React):

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

Paggamit ng useState at useEffect nang magkasama para sa pagkuha ng datos

Isa sa mga pinakakaraniwang kombinasyon sa totoong mundo ay ang paggamit ng useState at useEffect para kumuha ng datos mula sa isang APIPinapanatili mo ang data (at marahil ang mga flag ng paglo-load/error) sa estado, at isinasagawa ang kahilingan sa isang epekto na tumatakbo kapag naka-mount ang component o kapag nagbago ang ilang parameter.

Ganito ang hitsura ng isang pangunahing pattern para sa pagkuha ng data kapag naka-mount na:

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>
  );
}

Dito, tinitiyak ng walang laman na dependency array na ang kahilingan ay tatakbo nang eksaktong isang besesAng panloob ignore Ang flag ay isang simpleng paraan upang maiwasan ang pagtatakda ng estado sa isang hindi naka-mount na bahagi kung sakaling mahuli ang paglutas ng kahilingan.

Karaniwan din ang pagdaragdag ng loading flag at pagpapakita ng spinner o placeholder habang paparating ang data.:

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>
  );
};

Kung ang iyong query ay nakadepende sa isang parameter (tulad ng kategorya, filter, o parameter ng ruta), idagdag ang parameter na iyon sa dependency array kaya ang epekto ay babalik kapag nagbago ito:

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

  fetchItems();
}, );

Pag-iisip sa "mga epekto sa bawat render" vs "mga lifecycle"

Kung sanay ka na sa mga bahagi ng klase, maaaring nakakaakit na i-mind map ang mga ito useEffect para i-mount/i-update/i-unmount ang mga pamamaraan, ngunit kadalasan ay humahantong iyon sa mas maraming kalituhan. Ang isang mas simpleng mental na modelo ay: "ang mga epekto ay tumatakbo pagkatapos ng mga render, at maaaring malinis bago ang susunod na pagpapatakbo".

Sa mga klase, madalas mong kinailangan na doblehin ang lohika sa pagitan ng componentDidMount at componentDidUpdate dahil gusto mong tumakbo ang parehong effect sa mount at sa mga update. Sa mga hook, nawawala ang duplication na iyon: isang effect lang ang sumasakop sa parehong kaso, at ang React ang bahala sa paglilinis sa pagitan ng mga pagpapatakbo.

Tinatanggal din ng disenyong ito ang isang buong klase ng mga bug tungkol sa hindi wastong paghawak ng mga update.Halimbawa, sa isang component ng klase na nag-subscribe sa online status ng isang kaibigan, madaling makalimutang mag-subscribe muli kapag props.friend mga pagbabago, na nagdudulot ng mga lumang subscription o mga pag-crash kapag na-unmount. Gamit ang useEffect na naglilista friend.id Bilang isang dependency, awtomatikong patatakbuhin ng React ang paglilinis para sa dating kaibigan at ang pag-setup para sa bago.

Tandaan na sa pagbuo ng Strict Mode, sadyang pinapatakbo ng React ang iyong setup + cleanup cycle nang dalawang beses sa mount.Hindi ito nangyayari sa produksyon, ngunit isa itong kapaki-pakinabang na stress test upang kumpirmahin na talagang naaalis ng iyong paglilinis ang lahat at na ang iyong effect ay ligtas na maaaring tumakbo nang maraming beses.

Pag-optimize at pag-troubleshoot ng paggamit ng Epekto ng pag-uugali

Kapag ang isang epekto ay mas madalas na tumatakbo kaysa sa inaasahan mo, ang unang bagay na dapat suriin ay ang dependency arrayMaaaring magbago ang dependency sa bawat render (karaniwan sa mga inline object/function) o nakalimutan mo talagang tukuyin ang array.

Ang pag-log ng mga halaga ng dependency ay isang mabilis na paraan upang mag-debug:

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

Kung makakakita ka ng iba't ibang log sa bawat pagkakataon, siyasatin kung aling dependency ang talagang nagbabago.Madalas kang makakakita ng inline na object o arrow function na nililikha muli sa bawat render. Paglilipat ng paglikha ng object sa loob ng effect, o pag-aangat ng mga function sa labas ng component, o pag-memoize ng mga ito gamit ang useCallback maaaring patatagin ang mga dependency kung kinakailangan.

Nangyayari ang mga infinite loop kapag ang isang epekto ay parehong nakadepende sa isang halaga at walang kondisyong ina-update ang parehong halagang iyon. Halimbawa:

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

Sa bawat oras count mga pagbabago, ang epekto ay tumatakbo, mga update count muli, nagti-trigger ng isa pang render, at iba paPara masira ang padron na iyan, isaalang-alang kung ang state update ay tunay na kabilang sa isang effect, kung dapat ba itong i-trigger ng isang user interaction, o kung maaari kang umasa sa ibang value.

Minsan gusto mong basahin ang pinakabagong halaga ng ilang estado o props sa loob ng isang effect nang hindi nati-trigger ng halagang iyon ang isang re-run.Sa mga advanced na senaryo na iyon, ang mga mas bagong API tulad ng "mga kaganapan sa epekto" (sa pamamagitan ng useEffectEvent sa mga dokumento ng React) o mga ref ay makakatulong, ngunit para sa karamihan ng mga praktikal na kaso, ang pananatiling tapat sa mga dependency ay mas ligtas at mas simple.

Pagsasama-samahin ang lahat, gamit ang useState at useEffect wastong bumababa sa ilang pangunahing gawi: panatilihing maliit at nakapokus ang estado, mas gusto ang mga functional update kapag kumukuha ng bagong estado mula sa luma, istruktura ang mga epekto batay sa mga pares ng pag-setup/paglilinis, maging tapat at tahasan sa mga dependency array, at palaging igalang ang mga patakaran ng mga hook upang mapagkakatiwalaang masubaybayan ng React kung saan nararapat. Kapag sinusunod mo ang mga prinsipyong iyon, nananatiling mahuhulaan ang iyong mga bahagi, kumikilos ang iyong mga side effect, at nagiging mas madaling umunlad ang iyong React codebase habang lumalaki ang iyong app.

Kaugnay na artikulo:
Solved: Paano mag-install ng react native hooks gamit ang
Kaugnay na mga post: