# Što ćete naučiti#
Ovaj vodič daje ponovljiv workflow za profiliranje performansi i memoizaciju u Reactu u 2026.: prvo mjerite, pronađite stvarno usko grlo, pa primijenite ciljane popravke.
Naučit ćete kako koristiti React DevTools Profiler, why-did-you-render i osnovne metrike preglednika za dijagnostiku sporih interakcija, a zatim sigurno primijeniti memoizaciju, stabilne props i virtualizaciju lista.
Ako gradite u Next.js, pročitajte i naš vodič o React Server Components jer prebacivanje posla s klijenta može ukloniti čitave kategorije problema s performansama.
# Zašto React sučelja djeluju sporo u 2026.#
Većina prijava “sporog Reacta” i dalje se svodi na jedno od ovoga:
- Previše posla po interakciji: skupi renderi, teške izračune ili velika DOM stabla.
- Previše rendera: aplikacija radi ispravan posao, ali ga ponavlja zbog nestabilnih props ili lošeg smještaja state-a.
- Previše JavaScripta na main threadu: third-party skripte, hydration, analitika ili veliki bundleovi.
- Uska grla mreže i asseta: spore slike, fontovi ili API pozivi koji blokiraju ažuriranje UI-ja.
React 18 i 19 poboljšali su scheduling i concurrency, ali automatski ne uklanjaju rasipanje. Vaš je zadatak identificirati što se stvarno događa u vašoj aplikaciji, a ne što pretpostavljate da se događa.
ℹ️ Napomena: “Spor commit” u React Profileru može biti uzrokovan veličinom DOM-a, layout thrashingom ili skupim efektima. Rješenje može biti izvan React koda, pa uvijek potvrdite i browser profiliranjem.
Za širi pristup performansama izvan React renderiranja, pogledajte Optimizacija performansi web stranice.
# Preduvjeti i postavljanje alata#
Koristite ovu checklistu kako biste bili sigurni da su rezultati profiliranja pouzdani.
| Zahtjev | Preporuka | Napomene |
|---|---|---|
| React DevTools | Najnoviji stable | Potreban Profiler tab |
| Chrome DevTools | Najnoviji stable | Performance panel, long tasks |
| Node.js | 20+ | Česta osnova za moderne toolchaine |
| Build mode | Što bliže produkciji | Dev mode može prenaglasiti cijene renderiranja |
| Source maps | Uključeno | Čini traceove čitljivima |
| why-did-you-render | Najnoviji | Koristite samo u developmentu |
Profilirajte u okruženju sličnom produkciji#
Ako profilirate u developmentu, mogli biste loviti duhove. React namjerno dodaje provjere i dodatni posao u dev modu.
Praktične opcije:
- 1Pokrenite production build lokalno i testirajte na njemu.
- 2Koristite staging okruženje s produkcijskim flagovima.
- 3Koristite real user monitoring na stvarnom prometu.
Ako koristite Next.js, production build možete pokrenuti ovako:
npm run build
npm run start# Korak 1: Definirajte “sporo” kroz osnovne metrike#
Prije nego što dirate kod, definirajte cilj u mjerljivim terminima. Ne treba vam kompletna observability platforma da biste krenuli.
Minimalne metrike koje su bitne#
| Metrika | Cilj (praktično) | Kako mjeriti |
|---|---|---|
| Latencija interakcije | manje od 100 ms djeluje trenutačno | ručno testiranje + Profiler oznake |
| Trajanje React commit-a | izbjegavati česte commit-e dulje od 16 ms | React DevTools Profiler |
| Long tasks | držati pod kontrolom, izbjegavati “burstove” | Chrome Performance panel |
| Core Web Vitals | good pragovi | field podaci, Lighthouse kao baseline |
Koristite ih kao smjernice, ne kao apsolute. Složen dashboard može tolerirati nekoliko commit-a od 30 ms, ali ponavljani commit-i od 30 ms tijekom tipkanja djelovat će kao da je aplikacija pokvarena.
Napravite jedan ponovljiv scenarij#
Odaberite jedan korisnički tok koji jasno djeluje sporo, npr.:
- tipkanje u search polje
- otvaranje modala s velikom formom
- odabir filtera na listi proizvoda
- širenje retka u data tablici
Zapišite ga kao skriptu kako biste ga mogli ponoviti nakon svake promjene.
💡 Savjet: Snimite kratki screen capture “sporog” ponašanja. Pomaže potvrditi poboljšanja i sprječava da se regresije odbace uz “kod mene je okej”.
# Korak 2: Profilirajte interakciju s React DevTools Profilerom#
React DevTools Profiler odgovara na dva ključna pitanja:
- 1Koje su se komponente renderirale?
- 2Koliko je to trajalo i koje su bile rasipne?
Kako snimiti smislen profil#
- 1Otvorite React DevTools i idite na Profiler tab.
- 2Kliknite record.
- 3Izvedite točno tu sporu interakciju jednom ili dvaput.
- 4Zaustavite snimanje.
- 5Pronađite commit koji odgovara interakciji.
Fokusirajte se na:
- skokove u commit duration
- komponente s visokim self time
- komponente koje se re-renderiraju više puta tijekom jedne interakcije
Kako interpretirati flamegraph i ranked view#
Koristite oba:
- Ranked view da vidite koje su komponente bile najskuplje u tom commitu.
- Flamegraph da vidite put renderiranja i koja grana dominira.
Uobičajen obrazac kod sporih sučelja:
- mala promjena state-a uzrokuje re-render komponente visokog nivoa
- taj re-render se kaskadno širi na veliko podstablo: stavke liste, chartove, polja forme
- mnoge od tih child komponenti se vizualno uopće nisu promijenile
Kako izgledaju “wasted renders”#
Ako se komponenta renderira, ali joj se output ne mijenja, to je odlična meta za:
- spuštanje state-a niže
- stabiliziranje props
- memoizaciju
Ne nagađajte. Potvrdite razlog re-renderiranja prije nego dodate React.memo.
# Korak 3: Potvrdite uzroke re-renderiranja s why-did-you-render#
React DevTools govori što se renderiralo, ali ne uvijek i zašto. why-did-you-render pomaže otkriti koji su se props ili hookovi promijenili i okinuli render.
Instalirajte i uključite why-did-you-render#
Držite ga samo za dev.
npm install --save-dev @welldone-software/why-did-you-renderNapravite mali setup file i učitajte ga samo u developmentu. Točna lokacija ovisi o vašem stacku, ali ključ je da ga ne šaljete u produkciju.
// wdyr.js
import React from "react";
if (process.env.NODE_ENV === "development") {
const whyDidYouRender = require("@welldone-software/why-did-you-render");
whyDidYouRender(React, { trackAllPureComponents: true });
}Označite specifične komponente koje želite pratiti:
// Component.js
import React from "react";
function Row(props) {
return <div>{props.name}</div>;
}
Row.whyDidYouRender = true;
export default React.memo(Row);Na što paziti u console outputu#
Tipični krivci:
- props koji mijenjaju identitet pri svakom renderu: arrayi, objekti, funkcije
- derived data izračunata inline
childrenkoji se nepotrebno ponovno grade- context vrijednosti koje se recreiraju pri svakom renderu
Cilj je da uzrok re-renderiranja bude očit i popravljiv, ne da “utišate” logove memoizacijom svega.
⚠️ Upozorenje: Lako je “optimizirati” tako da memoizirate komponentu, a i dalje prosljeđujete nestabilne props. To često pogorša performanse: platite cijenu usporedbe u memoizaciji i svejedno se re-renderirate.
# Korak 4: Popravite “velika tri”: smještaj state-a, stabilni props i derived data#
Prije memoizacije, popravite arhitekturne probleme koji stvaraju render kaskade. Ako je strukturu komponenti već teško pratiti, pogledajte Arhitektura React komponenti za skalabilne design sustave i uskladite granice oko vlasništva nad state-om.
1) Spustite state što niže#
Ako je state filter inputa u parentu koji ujedno renderira veliku listu, svaki pritisak tipke može re-renderirati listu.
Praktičan refaktor:
- Držite state inputa unutar input komponente.
- Dižite state samo kada ga više siblinga stvarno treba.
- URL state ili global state koristite selektivno, ne po defaultu.
2) Stabilizirajte props s useMemo i useCallback samo gdje je bitno#
Nestabilni props forsiraju rendere čak i ako su vrijednosti “logički iste”.
| Tip props | Česta greška | Rješenje |
|---|---|---|
| Object props | options={{ a: 1 }} inline | useMemo za objekt |
| Array props | items={data.map(...)} inline | useMemo za derived arraye |
| Function props | onClick={() => ...} inline | useCallback kada se prosljeđuje duboko |
| Children | složeni children inline | izdvojiti ili memoizirati podstabla |
Primjer: stabilizacija konfiguracijskog objekta.
const columns = useMemo(() => {
return [
{ key: "name", label: "Name" },
{ key: "price", label: "Price" },
];
}, []);Primjer: stabilizacija handlera samo kad je potrebno.
const onRowClick = useCallback((id) => {
setSelectedId(id);
}, []);Ako callback ovisi o vrijednostima, i dalje će se mijenjati kad se promijene dependencies. To može biti u redu. Cilj je zaustaviti nepotrebne promjene, ne “zamrznuti” aplikaciju.
3) Izbjegavajte skupu derived data u renderu#
Ako sortirate, grupirate ili računate agregate na svakom renderu, plaćate ponavljajući trošak.
Tipične skupe operacije:
- sortiranje velikih arraya
- izgradnja mapa i indeksa
- ponavljano parsiranje datuma
- transformacije s puno regex-a
Premjestite izračun:
- u
useMemoako su inputi stabilni - u selektore ako koristite global state
- na server, ako je moguće
Ovdje Server Components mogu biti velik dobitak: gurnite skupo formatiranje i agregacije na server i pošaljite podatke spremne za renderiranje. Pogledajte Vodič za React Server Components.
# Korak 5: Smjernice za memoizaciju koje stvarno rade#
Memoizacija je alat, ne strategija. Koristite je tamo gdje profiliranje pokaže rasipanje i gdje props možete držati stabilnima.
React.memo: kada pomaže#
React.memo pomaže kada:
- komponenta se često renderira
- renderiranje nije trivijalno
- props su većinom vremena stabilni
- re-renderi su uglavnom identičan output
React.memo često ne pomaže kada:
- props se mijenjaju svaki put zbog promjena identiteta
- komponenta je mala i jeftina
- oslanjate se na implicitne re-render-e da UI ostane konzistentan
Primjer:
const PriceCell = React.memo(function PriceCell({ value, currency }) {
return (
<span>
{value} {currency}
</span>
);
});useMemo: koristite za skupe izračune, ne za kozmetiku#
Dobri use caseovi:
- sortiranje, filtriranje, grupiranje
- izgradnja lookup mapa
- memoizacija teških child stabala
Loši use caseovi:
- memoizacija malih spajanja stringova
- memoizacija trivijalnih objekata koji se ne prosljeđuju kao props
Pravilo iz prakse: ako se cijena izračuna ne vidi u Profiler self time, nemojte je memoizirati.
useCallback: koristite ga da memoizirani children ostanu memoizirani#
useCallback je uglavnom koristan kada:
- handlere prosljeđujete
React.memochild komponentama - promjena identiteta handlera uzrokuje re-render childa
- duboko stablo ovisi o tom handleru
Ne koristite useCallback svugdje “za svaki slučaj”. Dodaje overhead i čini kod težim za čitanje.
Custom usporedbe: rijetko se isplate#
React.memo(Component, areEqual) može pomoći u posebnim slučajevima, ali je maintenance zamka.
Koristite samo kada:
- props su veliki objekti
- možete pouzdano usporediti mali podskup
- imate testove da izbjegnete bugove zastarjelog UI-ja
Ako dodate custom usporedbe, dokumentirajte pretpostavke i provjerite profiliranjem.
# Korak 6: Obrasci renderiranja za velika sučelja#
Kada je DOM velik, memoizacija vas neće spasiti. Morate renderirati manje.
Virtualizirajte duge liste i tablice#
Ako renderirate 1.000 redaka, usko grlo može biti DOM, layout i painting, ne React. Virtualizacija obično renderira samo ono što je vidljivo plus mali buffer.
Praktični znakovi da trebate virtualizaciju:
- scroll “šteka”
- commit-i su ok, ali browser je zauzet
- Performance panel pokazuje puno vremena u layoutu i paintu
Često korištene biblioteke:
react-windowreact-virtualized- framework-specifični data gridovi s ugrađenom virtualizacijom
Minimalni primjer s react-window:
import { FixedSizeList as List } from "react-window";
function VirtualList({ items }) {
return (
<List height={500} itemCount={items.length} itemSize={36} width="100%">
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</List>
);
}Podijelite skupi UI progresivnim renderiranjem#
Ako otvaranje modala uzrokuje veliki commit, renderirajte shell prvo i odgodite teške sekcije:
- renderirajte prvo above-the-fold
- lazy loadajte chartove i editore
- suspense granice koristite promišljeno
To poboljšava percipiranu brzinu, čak i ako je ukupni posao sličan.
Izbjegnite “global rerender” okidače#
Česti okidači:
- stavljanje često promjenjivih vrijednosti u React Context
- prosljeđivanje velikih context vrijednosti koje se često mijenjaju
- spremanje kratkotrajnog UI state-a u globalne storeove
Ako morate koristiti context, razdvojite contexte po učestalosti promjena i držite vrijednosti stabilnima.
# Korak 7: Potvrdite poboljšanja browser profiliranjem#
React Profiler je nužan, ali nije dovoljan. Promjena u Reactu koja smanji commit time i dalje može ostaviti UI sporim zbog layouta, painta ili long tasks.
Koristite Chrome Performance panel za isti scenarij#
- 1Otvorite Chrome DevTools Performance.
- 2Pokrenite snimanje.
- 3Izvedite interakciju.
- 4Zaustavite.
- 5Potražite:
- long tasks na main threadu
- teški layout i paint
- event handlere koji blokiraju input
Uskladite vremenske oznake s React commit-ima. Ako su commit-i mali, ali je main thread zauzet, tražite:
- skupe obrasce mjerenja DOM-a
- sinkroni pristup storageu
- teške third-party skripte
- velike slike ili font swapove koji utječu na layout
Praktična definicija “gotovo”#
Gotovi ste kada:
- interakcija djeluje brzo na hardveru srednje klase
- skokovi u commit duration su smanjeni ili uklonjeni
- long tasks su smanjeni tijekom interakcije
- niste uveli regresije u ispravnosti
Ako možete, validirajte field podacima. Lighthouse je baseline; stvarni korisnici su završni test.
# Česte zamke u radu na React performansama#
- 1Preuranjena optimizacija — Memoizacija bez profiliranja često povećava kompleksnost i može pogoršati performanse zbog dodatnih usporedbi.
- 2Stabiliziranje svega — Pretjerivanje s
useMemoiuseCallbackotežava održavanje i ne garantira manje rendera. - 3Ignoriranje toka podataka — Loš smještaj state-a stvara render kaskade koje memoizacija ne može u potpunosti sakriti.
- 4Pogrešna upotreba contexta — Stavljanje brzo promjenjivih vrijednosti u context re-renderira sve consumere.
- 5Miješanje render time-a i ukupnog vremena — Brz React render i dalje može rezultirati sporim DOM ažuriranjima zbog layouta i painta.
- 6Mjerenje u dev modu — Dev-only provjere iskrivljuju rezultate i mogu vas navesti da popravljate nepostojeće probleme.
🎯 Ključna poruka: Profiliranje nije jednokratna aktivnost. Stvorite naviku: mjerite, promijenite jednu stvar, ponovno mjerite i držite kratku listu scenarija koji moraju ostati brzi.
# Checklist korak po korak koju možete ponovno koristiti#
Koristite ovaj redoslijed za svaki performance ticket:
- 1Definirajte skriptu spore interakcije i ciljnu metriku.
- 2Profilirajte s React DevTools Profilerom i identificirajte top self time komponente.
- 3Potvrdite razloge re-renderiranja s why-did-you-render.
- 4Popravite smještaj state-a i stabilizirajte props tamo gdje utječu na memoizirane granice.
- 5Dodajte memoizaciju samo tamo gdje profiliranje pokaže rasipanje.
- 6Virtualizirajte liste ili smanjite DOM ako je UI velik.
- 7Validirajte u Chrome Performance i pratite long tasks.
- 8Ponovno testirajte istu skriptu i dokumentirajte što se promijenilo.
# Ključne poruke#
- Prvo profilirajte stvarnu interakciju uz React DevTools Profiler, pa se fokusirajte na top self time komponente i skokove commit-a.
- Koristite why-did-you-render da potvrdite zašto se komponente re-renderiraju, posebno kod nestabilnih object, array i function props.
- Radije popravite smještaj state-a i stabilizirajte props nego da radite blanket memoizaciju; memoizirajte samo tamo gdje su rasipni renderi dokazani.
- Koristite virtualizaciju kada je veličina DOM-a usko grlo; memoizacija ne može kompenzirati renderiranje tisuća čvorova.
- Validirajte poboljšanja browser profiliranjem, ne samo React metrikama, i izbjegavajte odluke temeljene na mjerenjima u development modu.
# Zaključak#
React performanse u 2026. i dalje se svode na osnove: mjerite stvarne interakcije, smanjite nepotreban posao i renderirajte manje kada je DOM usko grlo. Ako želite drugo mišljenje o vašim Profiler traceovima ili trebate pomoć da ove obrasce pretvorite u dosljedan timski pristup, Samioda može napraviti audit vaše aplikacije i implementirati ciljane popravke u Reactu, Next.js ili Flutteru.
Kontaktirajte nas putem samioda.com i podijelite jednu snimku spore interakcije plus Profiler export, a mi ćemo odgovoriti s konkretnim planom optimizacije.
FAQ
Osnivač i senior developer u Samiodi. 8+ godina iskustva u izradi React, Next.js, Flutter i n8n rješenja za klijente diljem Europe.
Više iz kategorije Web razvoj
Sve →React Query u velikim aplikacijama: invalidacija cachea, paginacija i obrasci mutacija za stvarne aplikacije
Najbolje prakse invalidacije cachea u React Queryju za aplikacije iz stvarnog svijeta: skalabilan dizajn query keyjeva, strategija invalidacije, optimistična ažuriranja, infinite queryji i pozadinski refetch u Next.js App Routeru.
Next.js Edge Runtime vs Node.js Runtime (Vercel i Cloudflare): Što pokretati gdje
Praktičan okvir za odlučivanje između Next.js Edge Runtime i Node.js Runtime u 2026., s konkretnim primjerima, ograničenjima i završnom matricom use-caseova.
Server Actions u Next.js App Routeru: produkcijski obrasci za validaciju, greške i optimistični UI
Vodič spreman za produkciju za validaciju formi u Next.js Server Actions uz Zod, strukturirano rukovanje greškama, progresivno poboljšanje, optimistični UI i ograničavanje brzine — plus kada odabrati Server Actions umjesto API ruta.
Trebate pomoć s projektom?
Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.
Povezani članci
React Query u velikim aplikacijama: invalidacija cachea, paginacija i obrasci mutacija za stvarne aplikacije
Najbolje prakse invalidacije cachea u React Queryju za aplikacije iz stvarnog svijeta: skalabilan dizajn query keyjeva, strategija invalidacije, optimistična ažuriranja, infinite queryji i pozadinski refetch u Next.js App Routeru.
React obrasci u velikim aplikacijama: React Hook Form + Zod obrasci za složene proizvode
Najbolje prakse za React obrasce u velikim aplikacijama uz React Hook Form i Zod: validacija po shemi, višekratno upotrebljiva polja, asinkrone provjere, višekoračni tokovi, performanse, pristupačnost i obrasci integracije sa serverom/API-jem.
Objašnjene strategije cacheiranja u Next.js-u: SSR, SSG, ISR, Route Cache i SWR
Praktičan vodič kroz Next.js strategije cacheiranja u eri App Routera — kako se SSR, SSG, ISR, Route Cache, Data Cache i SWR uklapaju u cjelinu, uz tablice za odluke, primjere koda i česte zamke poput zastarjelih auth i tenant podataka.