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. 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).
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.
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.
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:
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.
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
.
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.
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:
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:
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.
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.
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).
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.
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.
Top comments (0)