# Uvod#
React PR može izgledati uredno, a svejedno isporučiti regresije: komponenta se rerenderira na svaki pritisak tipke, modal pogrešno zarobi fokus ili hook potajno stvori zastarjelo stanje. Cijena se pokaže kasnije kroz spore stranice, pritužbe korisnika i krhak kod koji nitko ne želi dirati.
Ovo je kontrolna lista za React code review koju koristimo u Samiodi za produkcijske aplikacije. Strukturirana je za stvarne PR-ove i uključuje primjere za komponente, hookove, stanje, renderiranje, pristupačnost i testiranje, uz copy-paste predložak za GitHub ili Linear te smjernice što automatizirati lint pravilima.
Za dublje urone, držite pri ruci i ovo tijekom reviewa: našu kontrolnu listu za pristupačnost u Reactu, naš vodič za profiliranje performansi u Reactu i našu kontrolnu listu za sigurnost web aplikacija.
# Kako koristiti ovu kontrolnu listu u stvarnim PR-ovima#
Kontrolna lista vrijedi samo ako smanjuje rizik bez usporavanja isporuke. Naš pristup je jednostavan: automatizirajte ono što se može automatizirati i sačuvajte ljudski review za stvari koje zahtijevaju prosudbu.
Workflow za review koji skalira#
- 1Prvo pokrenite automatizaciju: formatiranje, lint, typecheck, unit testove i osnovni a11y linting treba vrtjeti u CI-ju i lokalno.
- 2Brzo skenirajte diff: identificirajte što se promijenilo i što bi moglo biti pogođeno. Mala UI promjena i dalje može utjecati na renderiranje, upravljanje fokusom ili rukovanje greškama.
- 3Pregledajte po područjima rizika: performanse, a11y, održivost i testovi. Sekcije ispod mapiraju se direktno na to.
- 4Tražite izmjene uz razlog: reviewer treba objasniti utjecaj na korisnika, a ne osobne preferencije stila.
Što automatizirati, a što ručno pregledati#
| Kategorija | Automatizirati alatima | Ručno pregledati |
|---|---|---|
| Formatiranje | Prettier | Ništa |
| Type safety | TypeScript strict mode, tsc --noEmit | Dizajn API-ja, modeliranje domene |
| Kvaliteta koda | ESLint, React Hooks lint, pravila za import | Imenovanje, razdvajanje odgovornosti |
| Pristupačnost | eslint-plugin-jsx-a11y, Storybook a11y | Tokovi tipkovnicom, focus trapovi, složeni widgeti |
| Performanse | Build upozorenja, bundle analyzer | Okidači rerendera, granice memoizacije, velike liste |
| Testiranje | Jest, React Testing Library, coverage gateovi | Kvaliteta testova, realni korisnički scenariji |
| Sigurnost | Skeniranje dependencyja, skeniranje tajni | Autorizacijska logika, izloženost podataka |
ℹ️ Napomena: Statički alati uhvate puno toga, ali ne mogu u potpunosti validirati UX tipkovnicom, stvarni trošak rerendera ili pokrivaju li testovi smisleno ponašanje. Cilj je manje rasprava oko osnova i više pažnje na rizike za proizvod.
# Kontrolna lista, dio 1: Komponente i dizajn API-ja#
Dobre React komponente su predvidljive, lako se ponovno koriste i teško ih je pogrešno koristiti. Većina dugoročnih problema s održavanjem počinje nejasnim odgovornostima komponenti i nestabilnim API-jima.
Odgovornosti komponenti i granice#
Provjeri
- Komponenta radi jednu stvar. Ako dohvaća podatke, transformira ih i renderira više nepovezanih sekcija, kandidat je za refaktor.
- Logika kontejnera i prezentacijski UI su razdvojeni kad kompleksnost naraste.
- Zajednička logika se izvlači u hookove ili utilse, a ne duplicira.
Primjer: razdvoji podatke i UI kad ponašanje naraste
// Good: UI stays testable and reusable
type UserCardProps = {
user: { id: string; name: string; email: string };
onEdit: (id: string) => void;
};
export function UserCard({ user, onEdit }: UserCardProps) {
return (
<section aria-label="User">
<h2>{user.name}</h2>
<p>{user.email}</p>
<button type="button" onClick={() => onEdit(user.id)}>
Edit
</button>
</section>
);
}Props, defaulti i tipovi#
Provjeri
- Tipovi propsa su eksplicitni i minimalni. Izbjegavajte “bag of props” pristup.
- Optional propsi imaju jasne default vrijednosti, idealno na razini parametara.
- Nazivi callback propsa predstavljaju namjeru, ne detalje implementacije.
Čest “smell”
- Komponenta prima
data: anyisetData: anyi ponaša se kao mini-aplikacija.
Bolje
- Proslijediti samo podatke koji su potrebni i callbackove temeljene na namjeri poput
onSubmitilionSelect.
Greške, loading i empty stanja#
Provjeri
- Stanja greške i učitavanja su obrađena na pravoj razini.
- Empty stanja su namjerna i pristupačna.
- UI se nepotrebno ne “bljeska” između stanja.
Konkretno pitanje za review
- Ako API vrati prazan niz, što korisnik vidi i može li se oporaviti?
Kompozicija i varijante#
Provjeri
- Varijante koriste kompoziciju umjesto kaosa s uvjetima.
- Ako komponenta ima više od 3 do 4 propsa za varijante, razmislite o razdvajanju u podkomponente.
Primjer: izbjegnite eksploziju propsa
- Umjesto
variant="primary" size="sm" iconLeft="..." iconRight="..." loading, razmotriteButtonplusButton.IconplusButton.Loadingpattern gdje je prikladno.
# Kontrolna lista, dio 2: Hookovi i side effecti#
Bugovi u hookovima su skupi jer često prođu ručni QA i padnu tek u edge caseovima s tajmingom ili navigacijom.
Ispravnost React Hookova#
Provjeri
- Ovisnosti u
useEffectsu ispravne, bez “nedostaje, ali radi”. - Effecti se koriste za sinkronizaciju, ne za izvođenje UI stanja.
- Postoje cleanup funkcije za subscriptione, timere i event listenere.
Loše: effect se vrti prečesto i pokreće dodatno stanje
useEffect(() => {
setFormValue(user.name);
}, [user]);Bolje: ovisite o stvarnoj vrijednosti
useEffect(() => {
setFormValue(user.name);
}, [user.name]);Stabilni callbackovi i izvedene vrijednosti#
Provjeri
useCallbackiuseMemose koriste kad sprječavaju mjerljive rerendere ili skupi rad, ne kao default.- Izvedeni podaci se računaju iz izvornog stanja, ne spremaju se kao dodatno stanje.
“Smell”
const [filtered, setFiltered] = useState(...)gdje jefiltereduvijek izveden izitemsiquery.
Bolje
- Izračunati
filtereduz memoizaciju samo ako je skupo.
const filtered = useMemo(() => {
return items.filter((i) => i.name.toLowerCase().includes(query.toLowerCase()));
}, [items, query]);API custom hookova#
Provjeri
- Custom hookovi izlažu mali, koherentan shape povratne vrijednosti.
- Async hookovi imaju cancellation ili ignoriraju zastarjele odgovore.
- Error stanje je eksplicitno.
Primjer: ignoriraj zastarjele odgovore
useEffect(() => {
let active = true;
(async () => {
const result = await fetchUser(userId);
if (active) setUser(result);
})();
return () => {
active = false;
};
}, [userId]);⚠️ Upozorenje: Korištenje
useEffectza async posao bez zaštite od zastarjelih odgovora može prikazati pogrešne podatke nakon brze navigacije ili brzih promjena unosa.
# Kontrolna lista, dio 3: Upravljanje stanjem i tok podataka#
Većina React kompleksnosti je samonametnuta zbog nejasnog vlasništva nad stanjem. Review treba razjasniti što je lokalno stanje, što je server-state i što je izvedeno.
Vlasništvo nad stanjem i colocating statea#
Provjeri
- Stanje živi tamo gdje se koristi. “Liftajte” state gore samo kad je nužno.
- Izbjegavajte “global state by default”. Globalno stanje čini ovisnosti implicitnima.
- Koristite alate za server-state za server data pattern gdje ima smisla.
Konkretno pitanje za review
- Može li se ovo stanje izvesti iz propsa ili URL parametara umjesto da se sprema?
Izbjegavanje dupliciranog i nekonzistentnog stanja#
Provjeri
- Nema dupliciranih izvora istine poput
isOpeniselectedIdkoji mogu “odlutati”. - Kompleksni formovi koriste konzistentan pristup, ne ad-hoc stanje po polju.
Primjer “smell”
- I
itemsiitemsCountse spremaju odvojeno.
Reduceri za višekoračne interakcije#
Provjeri
- Kad tranzicije stanja nisu trivijalne, razmotrite
useReducerili state machine. - Nazivi akcija odražavaju korisničku namjeru.
Primjer: reducer pojašnjava tranzicije
type State = { status: "idle" | "saving" | "error" };
type Action = { type: "save" } | { type: "success" } | { type: "fail" };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "save":
return { status: "saving" };
case "success":
return { status: "idle" };
case "fail":
return { status: "error" };
default:
return state;
}
}# Kontrolna lista, dio 4: Renderiranje i performanse#
Problemi s performansama obično dolaze od nepotrebnih rerendera, skupog rada unutar rendera i neograničenih listi. Moderni React može biti brz, ali je također lako slučajno poništiti optimizacije.
Za detaljniji workflow s React DevTools Profilerom i patternima memoizacije, koristite naš vodič o profiliranju performansi u Reactu i patternima renderiranja.
Sprječavanje nepotrebnih rerendera#
Provjeri
- Props proslijeđeni memoiziranoj djeci su stabilni kad je to potrebno.
- Inline object i array literali se ne prosljeđuju dubokim stablima bez razloga.
- Event handleri su stabilni kad je bitno.
Loše: nestabilan prop uzrokuje rerendere djeteta
<Chart options={{ showLegend: true }} data={data} />Bolje: memoizirajte stabilne objekte
const chartOptions = useMemo(() => ({ showLegend: true }), []);
<Chart options={chartOptions} data={data} />Renderiranje lista i key-evi#
Provjeri
- Liste koriste stabilne key-eve iz podataka, ne indexe niza.
- Vrlo velike liste koriste virtualizaciju.
- Rad renderiranja skalira s veličinom podataka.
Konkretan benchmark
- Kad se približite stotinama DOM redaka, scrollanje i rerenderi postaju vidljivo lošiji na uređajima srednje klase. Virtualizacija se često isplati na 500 do 1.000 stavki, ovisno o kompleksnosti retka.
Uvjetno renderiranje i layout shiftovi#
Provjeri
- UI izbjegava skokove layouta gdje je moguće. Rezervirajte prostor za loadere i slike.
- Skeletoni ili placeholderi ne kvare navigaciju tipkovnicom.
Izbjegnite skupe izračune u renderu#
Provjeri
- Sortiranje, grupiranje i formatiranje se miče iz rendera ili memoizira.
- Formatiranje datuma i brojeva u velikim tablicama se cacheira ili unaprijed izračuna.
💡 Savjet: Ako se komponenta renderira više puta po jednoj korisničkoj interakciji, profilirajte prije dodavanja memoizacije. U mnogim aplikacijama najveći dobitak dolazi od uklanjanja redundantnog stanja i popravljanja ovisnosti effecta, a ne od omatanja svega u
memo.
# Kontrolna lista, dio 5: Pristupačnost i UX osnove#
Pristupačnost nije zadatak “za kasnije”. Review je najbolje mjesto za hvatanje problema prije nego postanu patterni koji se ponavljaju kroz cijeli codebase.
Za detaljnije ARIA i fokus smjernice koristite našu a11y kontrolnu listu za React pristupačnost.
Prvo semantički HTML#
Provjeri
- Koristite semantičke elemente prema namjeri:
buttonza akcije,aza navigaciju, naslove pravilnim redoslijedom. - Izbjegavajte klikabilne
divilispan. Ako baš mora postojati, trebaju keyboard handleri i role, ali to je i dalje drugo najbolje rješenje.
Primjer: ispravna upotreba buttona
<button type="button" onClick={onDelete} aria-label="Delete user">
Delete
</button>Pristupačna imena i labele#
Provjeri
- Inputi imaju labele povezane preko
htmlForiid. - Buttoni samo s ikonom imaju
aria-label. aria-describedbyse koristi za hint i error tekst.
Navigacija tipkovnicom i upravljanje fokusom#
Provjeri
- Modali zarobe fokus i vrate fokus pri zatvaranju.
- Dropdowni i meniji rade tipkovnicom, uključujući Escape za zatvaranje.
- Fokus je vidljiv i nije uklonjen.
Konkretno pitanje za review
- Možete li završiti cijeli flow koristeći samo Tab, Shift+Tab, Enter, Space i Escape?
ARIA upotreba#
Provjeri
- ARIA se koristi samo kad semantički HTML ne može izraziti ponašanje.
- Nema konfliktnih atributa poput
aria-hiddenna fokusabilnim elementima.
Motion i reduced motion#
Provjeri
- Animacije poštuju korisničke preferencije gdje je relevantno.
- UI s puno tranzicija ne blokira interakcije.
# Kontrolna lista, dio 6: Testiranje i QA signali#
Testovi trebaju štititi ponašanje do kojeg je korisnicima stalo, ne detalje implementacije. U reviewu tražimo testove koji padaju kad se UX pokvari.
Unit i component testovi#
Provjeri
- Testovi koriste user-centric upite i interakcije.
- Izbjegavajte testiranje internog stanja ili privatnih funkcija.
- Pokrijte error i empty stanja za kritične tokove.
Primjer: React Testing Library stil
it("submits the form", async () => {
render(<UserForm />);
await user.type(screen.getByLabelText("Email"), "a@b.com");
await user.click(screen.getByRole("button", { name: "Save" }));
expect(await screen.findByText("Saved")).toBeInTheDocument();
});Što testirati, po riziku#
| Područje | Minimalno očekivanje | Zašto je važno |
|---|---|---|
| Forme | Validacija, submit uspjeh, submit greška | Sprječava tihi gubitak podataka |
| Navigacija | Promjene ruta i ponašanje Back | Izbjegava slomljene flowove |
| Dozvole | UI stanja za neautorizirane korisnike | Sprječava izloženost podataka |
| Pristupačnost | Provjere role i name, osnove fokusa | Zaustavlja regresije rano |
| Viewovi osjetljivi na performanse | Smoke test za teške liste | Sprječava usporavanja |
E2E testovi za korisnička putovanja#
Provjeri
- Dodajte E2E testove za revenue-kritične tokove i kompleksne interakcije.
- Držite E2E fokusiranima. Previše krhkih testova usporava isporuku.
# Predložak kontrolne liste za PR (GitHub i Linear) za ponovnu upotrebu#
Kopirajte ovo u predložak opisa PR-a ili Linear issue. Držite obavezne stavke kratkima i natjerajte autore da razmišljaju o utjecaju, ne samo o implementaciji.
## Summary
- What changed:
- Why:
- User impact:
- Screenshots or video:
## React Code Review Checklist
### Components
- [ ] Component has a single clear responsibility
- [ ] Props are minimal, well-typed, and intent-based
- [ ] Loading, empty, and error states handled
### Hooks and effects
- [ ] `useEffect` dependencies correct and no stale closures
- [ ] Cleanup added for subscriptions, timers, and listeners
- [ ] Derived values are not duplicated in state
### State and data flow
- [ ] State ownership is clear and colocated where used
- [ ] No duplicated sources of truth
- [ ] Reducer or state machine considered for complex transitions
### Rendering and performance
- [ ] Lists use stable keys and avoid index keys
- [ ] No expensive computations inside render without memoization
- [ ] Memoization used only when it prevents real rerenders
### Accessibility
- [ ] Semantic elements used for interactive UI
- [ ] All inputs have labels and errors are announced
- [ ] Keyboard navigation works for the full flow
- [ ] Focus management handled for modals and overlays
### Testing
- [ ] Unit or component tests cover key behaviors and edge cases
- [ ] Tests query by role/label/text instead of implementation details
- [ ] E2E test added or updated for high-risk user journeys
## Risk notes
- Potential regressions:
- Rollback plan:# Što automatizirati lint pravilima i CI provjerama#
Ako reviewer više puta komentira isti problem, to treba postati pravilo. Cilj je manje ljudskog vremena potrošenog na greške koje se mogu spriječiti.
Preporučeni baseline za automatizaciju#
| Cilj | Alati | Što sprječava |
|---|---|---|
| Konzistentno formatiranje | Prettier u CI-ju i pre-commit | Rasprave o stilu i “bučne” diffove |
| Ispravnost hookova | eslint-plugin-react-hooks | Nedostajuće ovisnosti i stale closureove |
| Osnove a11y | eslint-plugin-jsx-a11y | Nedostajuće labele, pogrešne role, keyboard trapove |
| Higijena importova | eslint-plugin-import, pravila protiv ciklusa | Cirkularne ovisnosti i neuredne granice modula |
| Type safety | TypeScript strict i noImplicitAny | Runtime greške i nejasne ugovore |
| Test gate | Unit testovi u CI-ju, opcionalni coverage prag | Isporuka bez sigurnosne mreže |
Skica ESLint konfiguracije#
Neka bude kratko i pragmatično. Točna konfiguracija ovisi o vašem stacku, ali ovo su česti essentials.
module.exports = {
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
],
rules: {
"react/jsx-key": "error",
"react/self-closing-comp": "warn",
"jsx-a11y/label-has-associated-control": "error",
"jsx-a11y/no-noninteractive-element-interactions": "error",
"jsx-a11y/click-events-have-key-events": "error",
},
};CI provjere koje smatramo neupitnima#
- 1
npm run lint - 2
npm run typecheck - 3
npm test - 4Build korak za aplikaciju, posebno za Next.js rute
Dodajte sigurnosno skeniranje i provjere dependencyja kako codebase raste, usklađeno s našom kontrolnom listom za sigurnost web aplikacija.
🎯 Ključna poruka: Sve što se može pouzdano detektirati statičkom analizom treba automatizirati, kako bi revieweri mogli trošiti vrijeme na arhitekturu, UX, rizike performansi i tokove pristupačnosti.
# Ključne poruke#
- Automatizirajte ponovljive stavke reviewa pomoću ESLint-a, TypeScript-a i CI-ja, a zatim usmjerite ljudski review na UX, a11y i rizike performansi.
- Pregledajte komponente s fokusom na jasne odgovornosti, minimalne propse i namjerna loading, empty i error stanja.
- Provjerite hookove i effecte: ispravne ovisnosti, cleanup i izbjegavanje dupliciranja izvedenog stanja.
- Uhvatite regresije performansi rano provjerom stabilnih propsa, key-eva lista, skupog rada u renderu i virtualizacije za velike liste.
- Tretirajte pristupačnost kao područje prve klase u reviewu: semantički HTML, pristupačna imena, tokovi tipkovnicom i ispravno upravljanje fokusom.
- Tražite testove koji odražavaju ponašanje korisnika i pokrivaju kritične edge caseove, ne internu implementaciju.
# Zaključak#
Pouzdana kontrolna lista za React code review sprječava da se isti problemi stalno isporučuju: sporo renderiranje zbog nestabilnih propsa, nepristupačni UI patterni i krhka logika stanja. Ako standardizirate kontrolnu listu, automatizirate osnove i naučite reviewere da se fokusiraju na rizik, PR-ovi postaju brži, a aplikacija stabilnija.
Ako želite pomoć u uvođenju ove kontrolne liste kroz React ili Next.js codebase, ili trebate review trenutnih uskih grla u performansama i pristupačnosti, javite se Samiodi putem naših usluga web developmenta i prilagodit ćemo review proces vašem timu i ritmu izdanja.
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 →Next.js višeregionalne implementacije: obrasci za nižu latenciju na Vercelu i Cloudflareu
Praktičan vodič za Next.js višeregionalnu implementaciju u 2026.: edge rendering, regionalni SSR i obrasci lokalnosti podataka na Vercelu i Cloudflareu, uključujući upozorenja za baze podataka i kontrolnu listu za provjeru latencije.
Next.js monorepo s Turborepo + pnpm Workspaces: praktičan vodič za postavljanje u 2026.
Postavite monorepo spreman za produkciju za Next.js koristeći Turborepo i pnpm workspaces, sa zajedničkim paketima, lintanjem, testiranjem i CI cacheiranjem — uz trade-offove i zamke koje treba izbjeći.
Kontrolni popis pristupačnosti za React: ARIA, navigacija tipkovnicom, upravljanje fokusom i testiranje (2026.)
Kontrolni popis pristupačnosti za React usmjeren na developere, koji pokriva ARIA, navigaciju tipkovnicom, upravljanje fokusom i automatizirano testiranje s axe i Playwrightom — uz konkretne primjere za forme, modale, izbornike i toast obavijesti.
Trebate pomoć s projektom?
Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.
Povezani članci
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.
Kontrolni popis pristupačnosti za React: ARIA, navigacija tipkovnicom, upravljanje fokusom i testiranje (2026.)
Kontrolni popis pristupačnosti za React usmjeren na developere, koji pokriva ARIA, navigaciju tipkovnicom, upravljanje fokusom i automatizirano testiranje s axe i Playwrightom — uz konkretne primjere za forme, modale, izbornike i toast obavijesti.
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.