DEV Community

Cover image for Ukratko o useState hook u Reactu
Slaven Bunijevac
Slaven Bunijevac

Posted on

Ukratko o useState hook u Reactu

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).

basic example of a functional react component with useState hook

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:

example of useState initialization in react with a function call

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.

use function to call initialize state with a potentially expensive function
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.

replace name with count as state
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.

change count state on button click example

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.

multiple consecutive state changes in react

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.

multiple consecutive state changes in react with a function example

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.

object as state example

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.

change object state example

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.

change object state functionally example

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)