Kada kreiramo aplikacije u React-u, često se suočavamo sa pojmovima renderovanje (rendering) i rerenderovanje (re-rendering) komponenata. Iako ovo na prvi pogled može delovati jednostavno, stvari postaju zanimljive kada se upetljaju različiti state menadžment sistemi poput useState
, Redux
, ili kada ubacimo lifecycle hook-ove poput useEffect
. Ako želite da vaša aplikacija bude brza i efikasna, razumevanje ovih procesa je ključno.
Šta je Renderovanje?
Renderovanje je proces u kojem React prikazuje vaš korisnički interfejs (UI) na ekranu, bazirano na stanju (state
-u) ili prosleđenim vrednostima (props
). Kada se vaša komponenta prvi put prikazuje, to se zove prvo renderovanje.
Kako Funkcioniše Prvo Renderovanje (Initial Render)?
Kada se komponenta prvi put "montira" na DOM, evo šta se događa:
1. Inicijalizacija state-a:
Bilo da koristite useState
, props
ili Redux
, inicijalni state komponente se kreira.
2. Render funkcija:
React prolazi kroz JSX kod i generiše virtuelni DOM baziran na trenutnom stanju.
3. Kreira virtuelni DOM (Virtual DOM) za trenutno stanje komponente.
4. Upoređivanje (diffing):
Virtuelni DOM se upoređuje sa pravim DOM-om (pošto je prvi render, svi elementi će biti potpuno prikazani).
5. Prikazivanje:
Komponenta se prikazuje na ekranu.
Jednom kada je komponenta prikazana, sledeći izazov je rerenderovanje.
Rerenderovanje (Re-render): Kada i Zašto?
Rerenderovanje se dešava svaki put kada se stanje ili props promene. Da li ste kliknuli na dugme koje menja broj na ekranu? Promenili ste vrednost u Redux store-u? Sve te akcije mogu dovesti do toga da React ponovo prikaže komponentu, i tu dolazi do rerenderovanja.
Kako Funkcioniše Rerenderovanje?
Detekcija promene state-a:
Kod
useState
, kada pozovetesetState
, React zna da treba da ažurira komponentu.Kod
Redux
-a, kada se promeni vrednost ustore
, svaka komponenta povezana sa tim delom stanja se ponovo renderuje.
Trigger renderovanja:
Kada se stanje promeni, React kreira novi virtuelni DOM baziran na toj promeni.
Upoređivanje (diffing):
- React upoređuje novi virtuelni DOM sa starim i izračunava koje promene treba primeniti. Ovo je jedan od načina na koji React optimizuje renderovanje.
Prikaz promena:
- Nakon što su promene izračunate, React ih primenjuje na stvarni DOM. Tako se samo promenjeni delovi stranice ponovo prikazuju.
Koje Komponente Se Rerenderuju?
Nisu sve komponente pogođene svakom promenom. React rerenderuje samo one komponente koje:
Korisite lokalni state
:
Ako koristite useState
, komponenta se rerenderuje svaki put kada se pozove setState
.
Koriste Redux
state:
Ako vaša komponenta zavisi od Redux stanja (preko useSelector
ili connect
), biće ponovo renderovana kada se taj deo stanja promeni.
Koriste props
:
Ako se props
vrednost promeni, komponenta se ponovo renderuje sa novim vrednostima.
Optimizacija Rerenderovanja
Naravno, nije uvek idealno da se sve komponente bespotrebno ponovo renderuju. Ako želimo da aplikacija radi brzo i efikasno, evo nekoliko tehnika za optimizaciju:
1. Memoizacija Komponenti
React nudi funkcionalnost za memoizaciju komponenata preko React.memo
. Ako vaša komponenta ne zavisi od promena props ili state-a, možete je "zapamtiti", pa će se ponovo renderovati samo kada se relevantne vrednosti promene.
Primer:
const MemoizedComponent = React.memo(MyComponent);
2. Memoizacija Funkcija i Vrednosti
Da biste izbegli ponovno kreiranje funkcija ili vrednosti pri svakom renderu, koristite useCallback
za memoizaciju funkcija i useMemo
za memoizaciju vrednosti.
useCallback
vam omogućava da memoizujete funkciju i sprečite njeno ponovno kreiranje sve dok se zavisnosti ne promene.useMemo
memoizuje rezultat funkcije, tako da se ne računa ponovo na svakom renderu.
Primer:
const increment = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []);
const expensiveCalculation = useMemo(() => {
return count * 2;
}, [count]);
3. Redux Optimizacija
Ako koristite Redux, možete dodatno optimizovati aplikaciju pomoću memoizovanih selektora kao što je reselect. To omogućava da se izbegne ponovno renderovanje komponenata koje nisu pogođene promenom stanja.
Lifecycle Hook-ovi i Rerenderovanje
U klasičnim React klasama, koristili smo shouldComponentUpdate
da kontrolišemo kada će se komponenta ponovo renderovati. U funkcionalnim komponentama, ovaj koncept se može simulirati pomoću useEffect
i memoizacije.
Zaključak
Renderovanje i rerenderovanje su ključni za prikaz korisničkog interfejsa u React aplikacijama, ali pravilno razumevanje i optimizacija tih procesa može napraviti razliku između spore i super brze aplikacije. Ispravno korišćenje memoizacije
, useCallback
, useMemo
, kao i pažljivo rukovanje Redux
-om, pomaže da izbegnemo nepotrebne re-rendere i održimo naše aplikacije brzim i responzivnim.
Primer Koda: Renderovanje i Rerenderovanje u Akciji
Evo primera komponente koja koristi useState, Redux i memoizaciju da optimizuje renderovanje:
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useSelector, useDispatch } from 'react-redux';
const MyComponent = () => {
// Lokalni state
const [count, setCount] = useState(0);
// Redux state
const reduxValue = useSelector(state => state.someValue);
const dispatch = useDispatch();
// Memoizacija funkcije kako bi se izbeglo ponovno kreiranje na svakom renderu
const increment = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []);
// Memoizacija izračunate vrednosti
const expensiveCalculation = useMemo(() => {
return count * 2;
}, [count]);
// Efekat koji se pokreće samo pri promeni reduxValue
useEffect(() => {
console.log("Redux value changed:", reduxValue);
}, [reduxValue]);
return (
<div>
<p>Count: {count}</p>
<p>Expensive Calculation: {expensiveCalculation}</p>
<button onClick={increment}>Increment</button>
<button onClick={() => dispatch({ type: 'SOME_ACTION' })}>
Dispatch Redux Action
</button>
</div>
);
};
Kao što vidimo, ovde se koristi kombinacija lokalnog state
-a, Redux
-a, memoizacije i useEffect
hook-a da bi aplikacija bila što efikasnija.