Ukratko o useState hook u Reactu
Tags: javascript, web3, react
Published: 2024-03-26 07:21:06

## 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](https://dev.to/bslaven/class-komponente-i-funkcijske-komponente-u-reactu-52og) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgvm1su1le3ywzezphno.png)

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](https://dev.to/bslaven/destrukturisanje-u-javascriptu-tvoj-dobar-drugar-m9p).

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztoglmwh3dn84yybnbls.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90s61hat1jy9dto3ep68.png)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7fht4hnoudzlfbexti3.png)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpqkg1rtmuuu4cd36fsa.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fq2hp0lbppjc9a32e3dk.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vggdz9jo0znkax8tx99.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avmzjr2btgr6ef83d8es.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w2aw7ule2v4f9p0xo88h.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4gd0v2gt4xam8g6skv6z.png)

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.