DEV Community

Cover image for Samo nešto malo o 'useEffect' u Reactu
Slaven Bunijevac
Slaven Bunijevac

Posted on

Samo nešto malo o 'useEffect' u Reactu

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

basic useEffect component with comments

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

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

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

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

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

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:

Iprimitive comparison in JavaScript example

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

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

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

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

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)