Pitanje kontrole state-a u Reactu je jedno od najvažnijih kada radimo sa ovom bibliotekom. U ovom tekstu ću se baviti useState
funkcionalnošću, koja je donijela kontrolu state-a (state management) u funkcijske komponente koju do uvođenja hooks-a
nije imala mogućnost postavljanja i kontrole state-a.
Šta možete ovdje pročitati:
- Šta je useState hook?
- Osnovna upotreba.
- Promjena statea.
Šta je useState
hook?
Ovaj useState
hook je funkcionalnost koja nam omogućuje da postavljamo i kontrolišemo (mijenjamo) state u funkcijskim kompoentama.
State u suštini čine svi podaci u komponenti koji se će možda mijenjati vremenom, odnosno od jednog rendera do drugog.
Osnovna upotreba
Prva stvar koju treba istaći vezano za useState
hook je da on može biti korišten samo u funkcijskim komponentama. Class komponente imaju drugačiji način postavljanja i kontrole statea i to kroz this.state
objekat u konstruktoru.
Više o osnovnim razlikama, uključujući i state, između funkcijskih i class komponenti možete pročitati u ovom tekstu.
VAŽNA NAPOMENA: Veoma važna stavka za korištenje bilo kog hooks-a, pa samim time i useState
, je da njih obavezno treba pozivati na vrhu komponente, odnosno na najvišem nivou. Hooks-i se nikako ne mogu koristiti unutar petlji, funkcija, uslovno ili unutar bilo kog drugog bloka koda. Isključivo u najvišem nivou komponente.
Da bi se koristio useState
potrebno ga je uvesti iz react
biblioteke. Najčešća konvencija je da to bude na vrhu fajla u kom se koristi (red 1).
Prilikom postavljanja statea u funkcijskim komponentama useState
se poziva kao funkcija koja može dobija jedan argument. Ja sam u ovom primjeru kao kao taj argument postavio prazan string (red 4). Upravo taj argument će biti inicijalna vrijednost varijable name
.
Ista ta funkcija vraća dvije vrijednosti, koje sam destrukturisanjem izvukao u jedan niz. Detaljnije o destrukturisanju u JavaScriptu sam pisao u tekstu koji možete pročitati ovdje.
Postoji i drugi način korištenja useState
hooka, a to je da se veže direktno na React objekat kao React.useState()
. Ja lično smatram da je sintaksa sa uvozom mnogo ljepša za korištenje i čitanje.
Inicijalna vrijednost može biti bilo šta, string, broj, boolean, objekat ili niz. Inicijalna vrijednost može čak biti i rezultat pozivanja neke funkcije. Na primjer ovako:
Imam jedan jednostavan primjer funkcije (red 4) koja vraća prazan string. Onda sam tu funkciju jednostavno pozvao unutar useState
funkcije da dobijem gore navedeni prazan string kao inicijalnu vrijednost mog statea (red 9).
Međutim, ovakva inicijalizacija statea nosi jedan problem. Taj problem je što je pozivanje ove funkcije customNameSetter
potencijalno skupa/spora operacija. To je problem jer će ova funkcija biti pozivana svaki put kada se komponenta renderuje. Ne želimo da se potencijalno skupa operacija ponavlja svaki put kada se komponenta renderuje, ako nema potrebe za tim.
Rješenje za to je da se umjesto skupe operacije kao argument proslijedi obična funkcija koja će vratiti rezultat pozivanja skupe operacije.
Ovo će osigurati da potencijalno skupa funkcija customNameSetter
bude pozvana samo jednom, kada se komponenta prvi put renderuje.
Promjena statea
Jedna od osnovnih karakteristika statea u Reactu je da će se vremenom mijenjati. Upravo zato je default ponašanje useState
hook-a da vrati i drugu vrijednost u našem nizu, a to je funkcija kojom se mijenja state.
Kako bi na najbolji način prikazao promjenu statea, primijeniću primjer. Neću više koristiti varijablu name
nego count
, dakle neki brojač koji se stalno mijenja. Postaviću njegovu početnu vrijednost na nulu.
Funkcija setCount
će biti pozvana svaki put kad želim da promijenim vrijednost za count
. To ću uraditi tako što ću na klik tastera '+' povećati vrijednost varijable count
za jedan.
U gornjem primjeru vidim da ću trenutnoj vrijednosti za count
dodati jedan. Dakle nula plus jedan je jednako jedan. Jedan će onda biti prikazano na ekranu.
Ovakav pristup je sasvim ispravan, ali postoji jedna začkoljica. Ako pokušam, iz bilo kog razloga, da vežem više ovih promjena state jednu za drugom to neće funkcionisati.
Ovo neće promijeniti vrijednost count
varijable za četiri kako bi se moglo očekivati jer sam četiri puta pozvao setCount
. Vrijednost count
koja će biti prikazana na ekranu će biti 1.
Ovo se dešava jer React sakuplja sve ove pozive zajedno i svi pozivi setCount
funkcije mijenjaju state za sljedeći render.
Svaki poziv setCount
funkcije koristi inicijalnu vrijednost varijable count
koju povećava za jedan. Operacija će uvijek biti nula plus jedan daje jedan.
Da bi se ovo izbjeglo potrebno je koristiti funkcijsku verziju izmjene statea. Proslijedim 'updater' funkciju u setCount
i unutar nje mijenjam state na osnovu prethodnog statea. Ta funkcija ima automatski jedan parametar, taj parametar je prethodna vrijednost state, odnosno u našem primjeru varijable count
.
Ovdje je razlika u tome što React ne sakuplja ove 'updater' funkckije nego će ih u sljedećem renderu pozvait istim redoslijedom.
Imam funkciju koja vraća prethodni count
uvećan za jedan. Na ovaj način svaki sljedeći poziv setCount
funkcije će koristiti 'najsvježiju', odnosno posljednju vrijednost za count
. Kada prvi poziv setCount
poveća count
za jedan, sljedeći poziv će uzeti rezultat prethodnog poziva i njega uvećati za jedan, itd. itd.
Još jedna stvar kod izmjene statea na koju moramo obratiti pažnju je izmjena objekata i nizova. Recimo na primjer da imam state koji nosi podatke za jednog korisnika, user
.
Postavio sam inicijalnu vrijednost varijable da bude objekat koji ima dva elementa name
i age
. Obije ove vrijednosti će biti ispravno prikazane u ovom primjeru.
Međutim, ako pokušam na klik tastera da promijenim age
na 35, ne mogu jednostavno pozvati setUser
i promijeniti age
na 35.
Ovo ne mogu uraditi jer ću izgubiti name
iz svog statea. Mora se navesti ostatak objekta, pa onda dodati svojstvo koje mijenjam. Da bi to postigao moram ponovo koristiti funkcijsku verziju izmjene statea. Koristiću funkciju koja kao parametar dobija prethovnu verziju statea.
Iskoristio sam spread (...)
operator kojim sam sačuvao sva neizmjenjena svojstva, pa ih zajedno sa izmijenjenim vratio kao jedan objekat. Ovdje sam za primjer koristio objekat, ali sva ista pravila važe i za nizove.
U ranijem primjeru promjene count
varijable, kao i u ovom posljednjem primjeru sa promjenom user
varijable vidi se jedan zajednički obrazac kog se treba pridržavati kad je promjena statea u Reactu u pitanju. Taj obrazac je da se uvijek koristi funkcijska verzija izmjene statea kada nova zavisi od toga koja je bila prethodna vrijednost.
Na osnovu ovog se lako može postaviti pitanje zašto ne bi uvijek koristili funkcijsku verziju izmjene statea da bi bili sigurni. To se svakako može uraditi, ali u nekiim situacijama zaista nema potrebe. Ako nova vrijednost ne zavisi od stare ne mora se koristiti funkcijska verzija izmjena statea.
Top comments (0)