useState — ay isang built-in na React hook na nagpapahintulot sa mga functional component na pamahalaan ang lokal na state nang hindi ginagawang class component. Ipinakilala ng React 16.8 ang mga hooks, at ang useState ang naging pinaka-ginagamit sa kanila, na pumalit sa this.state at this.setState mula sa class approach. Ayon sa React Documentation (2025), mahigit 80% ng mga component sa modernong React application ay gumagamit ng useState para sa pamamahala ng data ng form, interface flags, at mga counter. Ang hook ay nagbabalik ng tuple na binubuo ng kasalukuyang halaga at setter function na nag-a-update ng state at nag-uumpisa ng re-render ng component.
Mga Pangunahing Punto
useState — ay ang pangunahing React hook, idinagdag sa bersyon 16.8, na nagbibigay sa mga functional component ng kakayahang mag-imbak at magbago ng lokal na state. Bago dumating ang mga hooks, ang state ay magagamit lamang sa mga class component sa pamamagitan ng this.state at this.setState, na ginagawang pampakita lamang ang mga functional component. Inalis ng useState ang limitasyong ito, na nagpapahintulot na isulat ang buong application sa mga functional component.
Ang hook ay tumatanggap ng isang argumento — ang paunang halaga ng state — at nagbabalik ng array ng dalawang elemento. Ang unang elemento ay ang kasalukuyang halaga ng state, ang pangalawa ay ang function para i-update ito. Ginagarantiya ng React na ang setter function ay stable at hindi nagbabago sa pagitan ng mga render, na nagpapahintulot ng ligtas na pagpasa nito sa mga child component at paggamit sa mga closure.
Ayon sa React DevTools Usage Survey (2024), ang useState ay ginagamit sa 96% ng mga React application, ginagawa itong pinakalaganap na hook sa ecosystem. Kahit sa mga application na gumagamit ng global state sa pamamagitan ng Redux o Zustand, ang lokal na state sa pamamagitan ng useState ay nananatiling pangunahing mekanismo ng pamamahala ng UI state — bukas na modals, halaga ng input field, aktibong tab.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Ang panloob na mekanismo ng useState ay nakabatay sa fiber node system ng React. Ang bawat component sa React ay kinakatawan ng fiber node na nag-iimbak ng nauugnay na listahan ng mga hooks sa anyo ng naka-link na listahan. Kapag ang component ay tumawag ng useState, ang React ay lumilikha ng bagong node sa listahang ito at nag-iimbak dito ng kasalukuyang halaga ng state at reference sa queue ng mga update.
Kapag tinawag ang setter function, hindi agad ina-update ng React ang state. Sa halip, inilalagay nito ang update sa queue (pending state queue), nag-iiskedyul ng re-render ng component, at sa susunod na render lamang kinakalkula ang bagong state batay sa luma at mga inilapat na update. Tinitiyak nito ang batching — kung sa isang event handler ay tinawag mo ang setter nang tatlong beses, igrupo ng React ang mga ito sa isang re-render.
Ayon sa React Team — React 18 Working Group (2024), ang automatic batching ay pinalawak sa React 18: ngayon ang mga state update ay naka-grupo hindi lamang sa mga event handler, kundi pati na rin sa setTimeout, Promise callbacks, at native handler. Nagbigay ito ng pagtaas ng performance hanggang 30% sa mga senaryo na may maraming state update.
Kapag ang bagong state ay nakadepende sa nauna, gamitin ang functional form ng setter: setCount(prev => prev + 1). Ipinapasa ng React sa function ang aktwal na halaga ng state sa oras ng paglalapat ng update, na ginagarantiya ang kawastuhan kahit sa naka-batch na mga update. Kung wala ang functional form, ang setCount(count + 1) ay maaaring gumamit ng lumang halaga kung ito ay tinawag nang ilang beses nang sunod-sunod.
// Lazy initialization — isang beses lang tumatakbo
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3
// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)
Ang pangunahing syntax ng useState ay napakaikli: const [state, setState] = useState(initialValue). Ang paunang halaga ay ginagamit lamang sa unang render; sa mga susunod na render ay binabalewala ito ng React at ibinabalik ang kasalukuyang naka-imbak na halaga. Kung ang paunang pagkalkula ay nangangailangan ng mamahaling operasyon, magpasa ng initializer function: useState(() => computeExpensiveInitial()).
Ang lazy initialization (lazy initial state) ay lalong mahalaga kapag ang paunang halaga ay nagmumula sa localStorage, kumplikadong pagbabago ng data, o pag-parse ng URL parameters. Tinatawag ng React ang initializer function nang isang beses lamang — sa pag-mount ng component, na nakatipid ng resources sa mga susunod na render. Kung walang lazy initialization, ang mamahaling expression ay kakalkulahin sa bawat render, kahit na ang resulta nito ay binabalewala.
| Form | Halimbawa | Kailan gagamitin |
|---|---|---|
| Direkta | useState(0) | Simpleng paunang halaga |
| Lazy | useState(() => compute()) | Mamahaling paunang pagkalkula |
| Functional na setter | setState(prev => prev + 1) | Pag-update batay sa nauna |
| Direktang setter | setState(newValue) | Bagong halaga ay hindi nakadepende sa luma |
// State ng object — gumawa ng bagong reference
const [user, setUser] = useState(() => {
const saved = localStorage.getItem('user');
return saved ? JSON.parse(saved) : null;
});
useState ay gumagana nang maayos sa mga primitive (numero, string, boolean) at reference type (array, object). Ngunit may mahalagang pagkakaiba: para sa mga primitive, nakikita ng React ang pagbabago batay sa halaga, para sa mga object at array — batay sa reference. Ang pag-mutate ng umiiral na object nang hindi gumagawa ng bago ay hindi magdudulot ng re-render, dahil ang reference ay nanatiling pareho.
Kapag nagtatrabaho sa mga object at array, laging gumawa ng bagong kopya na may binagong data. Para sa mga object gamitin ang spread syntax: setUser(prev => ({...prev, name: newName})). Para sa mga array — mga method na nagbabalik ng bagong array: filter, map, concat, o spread syntax para sa pagdaragdag ng mga elemento. Ang mga mutation method tulad ng push, pop, splice nang direkta hindi gagana — balewalain sila ng React dahil hindi nagbago ang reference sa array.
// ✅ Tama: hooks sa pinakamataas na antas
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
setForm(prev => ({ ...prev, [field]: value }));
// ...
const [items, setItems] = useState([]);
const addItem = item =>
setItems(prev => [item, ...prev]);
Tulad ng lahat ng React hooks, ang useState ay sumusunod sa dalawang patakaran. Una: tawagin ang mga hooks lamang sa pinakamataas na antas ng component — hindi maaaring ilagay ang mga ito sa loob ng mga kondisyon, loop, o nested function. Tinitiyak nito na ang mga hooks ay tinatawag sa parehong pagkakasunud-sunod sa bawat render, na kritikal para sa panloob na naka-link na listahan ng React.
Ikalawang patakaran: tawagin ang mga hooks lamang mula sa mga functional React component o custom hooks. Huwag tawagin ang useState mula sa mga ordinaryong function, callback, o class component. Ang paglabag sa mga patakarang ito ay humahantong sa error na Invalid hook call, na nakikita ng React sa yugto ng pagpapatupad.
// ❌ Problema ng lumang closure
function GoodComponent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// ✅ Naayos gamit ang functional na update
}
// luma na ang counter!
function BadComponent() {
if (isLogged) {
const [user, setUser] = useState(null);
}
}
Ang pinakakaraniwang pagkakamali — direktang mutation ng mga object at array sa halip na gumawa ng mga bagong reference. Nasanay ang mga developer sa mutable style mula sa class component, kung saan ang this.state.user.name = “Bagong pangalan” ay gumagana (kahit hindi inirerekomenda). Sa mga functional component, ang ganitong mutation ay binabalewala lamang: hindi nakikita ng React ang pagbabago ng reference at hindi iginuguhit muli ang component.
Ang problema ng lumang closure (stale closure) ay nangyayari kapag ang callback na ipinasa sa useEffect o event handler ay “nahuhuli” ang lumang halaga ng state mula sa closure sa oras ng paggawa ng callback. Ang solusyon — gamitin ang functional form ng setter o isama ang mga kinakailangang halaga sa dependency array ng useEffect. Ayon sa React Documentation — Hooks FAQ (2025), ang mga lumang closure ay pangalawang pinakakaraniwang sanhi ng bugs sa hooks pagkatapos ng maling dependency array.
// ❌ Stale closure problem
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1); // count is stale!
}, 1000);
return () => clearInterval(timer);
}, []);
// ✅ Fixed with functional update
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
Mga Madalas Itanong
Oo, ngunit may pag-iingat. Para sa malalim na nested object, ang bawat antas ay nangangailangan ng pagkopya sa pag-update: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Kung mayroon kang mga object na may tatlo o higit pang antas ng nesting, isaalang-alang ang Immer (library para sa imutable na pag-update) o hatiin ang state sa maraming useState para sa iba't ibang antas.
useState ay asynchronous sa kahulugan na ang pagtawag ng setter ay hindi agad ina-update ang halaga. Inilalagay ng React ang update sa queue at isinasagawa ito sa susunod na render. Pagkatapos ng setCount(newValue), ang variable na count sa kasalukuyang function ay naglalaman pa rin ng lumang halaga. Ang bagong halaga ay magiging available lamang sa susunod na pagtawag ng component. Tinitiyak ng mekanismo ng batching na ang maraming pagtawag ay naka-grupo sa isang render.
Ang React ay magtapon ng error na Invalid hook call. Ang mga hooks ay maaari lamang tawagin sa loob ng mga functional React component o custom hooks (mga function na ang pangalan ay nagsisimula sa use). Ang limitasyong ito ay naka-embed sa implementasyon ng mga hooks: ginagamit nila ang fiber tree ng component para mag-imbak ng state, at sa labas ng component ang tree na ito ay hindi available.
useState ay angkop para sa simpleng independyenteng state (mga counter, input field, flag). useReducer ay mas mahusay kapag ang state ay isang kumplikadong object na may maraming field, ang update logic ay nakadepende sa uri ng aksyon, o ang susunod na state ay nangangailangan ng kumplikadong pagbabago. Praktikal na patakaran: kung mayroon kang higit sa tatlong magkakaugnay na state field — gamitin ang useReducer.
Ito ay ginawa para sa performance. Kung ang useState ay mag-a-update ng state nang synchronously, ang bawat pagtawag ng setter ay magdudulot ng agarang re-render, na hahantong sa maraming pag-redraw sa loob ng isang event handler. Ang batching, kung saan ang React ay nag-grupo ng mga update at nagsasagawa ng isang re-render, ay isang optimisasyon na ipinakilala noong React 16 at makabuluhang pinabuti sa React 18 gamit ang automatic batching.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din