Samo nešto malo o 'useEffect' u Reactu
Tags: webdev, javascript, react
Published: 2024-04-05 08:06:25

## Tokom svog životnog ciklusa komponenta će često koristiti neke eksterne sisteme ili API-eve radi funkcionalnosti koju oni donose.
## S obzirom da te konekcije često zavise od dinamičnih dijelova aplikacije ili komponente, npr. state-a koji se mijenja, potrebno je omogućiti komponenti da prati te dijelove, te da se u skladu sa potrebama reaguje, da se ponovo izvrši poziv na eksterni sistem ili eventualno da se prekine konekcija sa nekim eksternim sistemom.
## Tu na scenu stupa `useEffect` hook.
**NAPOMENA**: _Termin 'eksterni sistem' sam pozajmio iz React-ove [dokumentacije](https://react.dev/reference/react/useEffect). Oni 'eksternim sistemom' smatraju sve šta nije pod kontrolom React-a. To podrazumjeva dodavanje `eventListenera`, `setInterval()` metoda, te eventualni poziv na neki REST API resurs._


---

### Šta možete ovdje pročitati?
- **Šta je `useEffect` hook?**
- **Koji su parametri u `useEffect` hook?**
- **Primitivni i referentni tipovi.**
- **Šta radi `return` dio?**
- **Zaključak.**

---

#### Šta je `useEffect` hook?
Jedna od specijalnih funkcija koje komponenta ima na raspolaganju je `useEffect`. Ove specijalne funkcije se u React-u zovu hooks, pa ću ih i ja u ovom tekstu tako zvati.
Ova funkcija nam omogućuje da pratim bilo kakve sporedne efekte u komponenti. Svaki put kada pokušamo da se konektujemo na neki eksterni sistem vjerovatno će biti potrebno koristiti `useEffect`.
Svaki put kada se promijeni neki dinamični dio, npr. `state`, komponente/aplikacije `useEffect` će se koristiti da se prati da li treba nešto uraditi na osnovu izmijenjenih vrijednosti.
Kao i svaki hook u React-u, `useEffect` je neophodno koristiti, unutar komponente, na najvišem nivou (_top level_).


![basic useEffect component with comments](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rs9t66vv6j333uetsvdr.png)
---

#### Koji su parametri u `useEffect` hook?

Prvi parametar je funkcija koja će biti pozvana jednom sigurno, kada se komponenta prvi put postavi. U ovoj funkciji je sva funkcionalnost koju želim da obavim kada `useEffect` registruje promjenu. U ovoj funkciji mogu da spojim komponentu nekim eksternim sistemom.


![Some examples of events in useEffect](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90udf0zs28igvdeofdv9.png)

Ovo su samo neke od stvari koje se mogu uraditi unutar `useEffect` hook-a, s tim da neke od njih dolaze i sa određenim 'dodatnim objašnjenima'. Npr. slanje zahtjeva na neki API resurs (_red 9_) bi trebalo da se razdvoji od same logike komponente ili kroz neki drugi hook ili korištenjem neke dodatne biblioteke, ali o tome u nekom drugom tekstu.
Drugo objašnjenje je što svaki put kada se postavi neki 'event listener' (_red 6_) isti taj 'event listener' bi treblao skinuti kada se komponenta ukloni sa stranice. Više o tome u dijelu 'Šta radi `return` dio?'.

Drugi parametan prilikom pozivanja `useEffect` hooka je niz 'dependency-a' (_red 12_).

**NAPOMENA**: _Riječ 'zavisnost' jeste nezgodan prevod za 'dependency' u ovom kontekstu, ali ona odlično označava ono šta te vrijednosti predstavljaju i za šta služe. Više o tome u daljem tekstu. Treba imati u vidu da se u ovom tekstu mogu naći obije verzije, 'dependency' i 'zavisnost'._

Prvo šta treba naglasiti je da drugi parametar, niz dependency-a, nije neophodno navesti, kao što se vidi u ovom primjeru.

![useEffect example without a dependency array](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5osygh2omkdw9828albe.png)

Nedostatak ovog niza će značiti da će funkcija koja je prvi parametar biti pozvana svaki put kada se komponenta ponovo renderuje. U velikoj većini slučajeva, ako ne i uvijek, to ne želimo. Hook `useEffect` se bavi sporednim efektima, situacijama kada želimo da izađemo iz React-ovog ekosistema, te bi bilo previše da se to svaki put radi kada se komponenta renderuje.

Druga opcija za ovaj niz je da se ostavi prazan. Dakle, `useEffect` nema nikakvih dependency-a. Evo primjera:

![useEffect example witha an empty dependecy array](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ztudmgk75s42hbd6cz3.png)

U slučaju kada postavimo prazan niz, funkcija koja je prvi parametar će biti pozvana samo jednom, kada komponenta bude prvi put renderovana. Evo jednog primjera gdje imam `count` varijablu čiju vrijednost povećavam za jedan kada kliknem na `button`. Pored toga imam i `useEffect` sa praznim nizom dependency-a.

![useEffect example with empty dependency array and state change](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhiu9ln5ytjb3fqq48f6.png)

Kao što sam naveo u komentarima u primjeru, promjena state-a će uzrokovati da se komponenta ponovo renderuje, ali `useEffect` funkcija neće biti ponovo pozvana zato što je niz dependecy-a prazan.

Sada se postavlja pitanje šta se može staviti u ovaj niz? Odgovor je bilo šta, odnosno bilo koju vrijednost/varijablu koju želim da `useEffect` prati. Kao što prevod 'zavisnost' govori, u tom slučaju moj `useEffect` će **zavisiti** od te vrijednosti/varijable. Iskoristiću gore navedeni primjer i postaviti da varijablu `count` kao zavisnost u `useEffect`.


![useEffect tracks state change and reruns the function example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23tl7xwb6ey9nqnwzaiw.png)

U ovom slučaju `useEffect` zavisi od varijable `count` i pozvaće svoju funkciju prvi put kada se komponenta prvi put renderuje, te svaki put kada registruje promjenu u vrijednosti varijable `count`.

Prilikom postavljanja vrijednosti u niz dependency-a treba obratiti pažnju da sama funkcija ne mijenja tu varijablu. Jer ako funkcija mijenja varijablu od koje `useEffect` zavisi to će uzrokovati beskonačnu petlju.


---

#### Primitivni i referentni tipovi
U JavaScriptu postoje dvije vrste tipova podataka. Svi koji koriste React vjerovatno su u poznati sa referentnim i primitivnim tipovima. Detaljnije o razlikama između ova dva tipa sam pisao u tekstu koji možete pročitati [ovdje](https://dev.to/bslaven/tipovi-u-javascriptu-eef).

Evo kratkog sažetka razlike koja nam je bitna za današnju temu.

Primitivni tipovi u Javascriptu su `string`, `boolean`, `number`, `null`, `undefined`. Oni se porede po vrijednosti. Ako na primjer imam dvije varijable i obije nose vrijednost npr. broja 4 i probam da ih uporedim dobiću `true`. Evo još nekoliko primjera:


![Iprimitive comparison in JavaScript example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8w8xw00kdlrwdm9gcl3.png)

Ovo je očekivano ponašanje. Međutim, referentni tipovi se prilikom poređenja ponašaju malo drugačije. Referentni tipovi u JavaScriptu su objekti, nizovi i funkcije. Recimo npr. da imam dva objekta u primjeru dole:

![object comparison in JavaScritp example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyfhizflolzh01jw6jp3.png)


Poređenje dva objekta koji su po sadržaju identični daje `false` jer se objekti ne porede po vrijednosti/sadržaju, nego po referenci. Referenca upućuje na njihovu lokaciju u memoriji, a lokacija u memoriji dva objekta nije ista. Ovo je izuzetno važna poenta prilikom korištenja `useEffect` hook-a.


![object as a dependency in useEffect](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3cbsnnxzeo9pp89rgf0.png)

U ovom primjeru `useEffect` će biti pozvan svaki put kada promijenim 'count' iako taj `useEffect` uopšte ne koristi `count`, odnosno ne zavisi od njega. To se dešava zato što će se komponenta svaki put ponovo renderovati kada se promijeni state. Svaki put kada se komponenta ponovo renderuje ona će kreirati novi objekat `person`, sa novom referencom.

Prilikom novog renderovanja komponente `useEffect` će uporediti prethodnu vrijednost objekta i novu vrijednost objekta i oni će biti drugačiji. Biće drugačiji jer su to dva različita objekta po referenci. Kao što sam rekao, njihov sadržaj se nije promijenio, ali referenca jeste. Objekti po tome nisu isti i `useEffect` će bit ponovo pozvan.

Rješenje za ovo je da se pobrinemo da naš `useEffect` zavisi isključivo od primitivnih vrijednosti, koje se porede po vrijednosti, a ne po referenci.


![object property as a dependency in useEffect](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/er7abqathospkc598m6t.png)

U ovom slučaju iako je objekat `person` kreiran svaki put kada se komponenta ponovo renderuje, `useEffect` ne zavisi od objekta nego od primitivne vrijednosti `name` unutar tog objekta. Ako se vrijenost za `name` ne promijeni funkcija u `useEffect` neće biti pozvana prilikom novog renderovanja komponente.

---

#### Šta radi `return` dio?
Kao i svaka funkcija, funkcija koja je prvi parametar unutar `useEffect` ima svoju `return` vrijednost. Postavljanje `return` dijela **nije** obavezno. To je funkcija koja će biti pozvana kada se komponenta skine/obriše (_unmount_).


![example of useEffect cleanup function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w2zcjdfoeajta4m8xmk8.png)

Upravo u ovoj funkciji će se skinuti `eventListener` o kom sam govorio u ranijem dijelu ovog teksta. Ovdje se može prekinuti konekcija sa nekom sobom za chat ili će se zaustaviti neki postavljeni interval.

---

#### Zaključak

Iako na prvi pogled djeluje kao da su `useEffect` i neki drugi 'hooksi' zamjena za ono šta rade metode životnog ciklusa u `class` komponentama, najbolje je razmišljati o njima kao potpuno drugačiji pristup životnom ciklusu metoda. Oba pristupa imaju svoju primjenu u zavisnosti koje komponente se koriste. Više o osnovnim razlikama između funkcijskih i `class` komponenti u React-u sam pisao u tekstu koji možete pročitati [ovdje](https://dev.to/bslaven/class-komponente-i-funkcijske-komponente-u-reactu-52og).

##### U kratkim crtama:
- Obavezno navedite niz dependecy-a/zavisnosti, makar on bio prazan.
- Nemojte stavljati objekte u niz dependecy-a.
- Ne dozvolite da `useEffect` zavisi od vrijednosti/varijable koju sam mijenja.
- Uvijek očistite/uklonite konekciju sa eksternim sistemom prije skidnaja komponente.