Tři pravidla pro vedlejší efekty v Reactu
Pokud jste s Reactem pracovali už delší dobu, pravděpodobně jste někdy zírali na dependency pole useEffectu a přemýšleli, proč se komponenta re-renderuje v nekonečné smyčce. Nebo jste narazili na chybu „Hydration failed“, protože něco v komponentě neodpovídalo výstupu ze serveru.
- •Co je to vedlejší efekt a jak souvisí se vztahem v = f(s)
- •Proč tělo komponenty musí zůstat čistým výpočtem (Rule #0)
- •Kdy patří vedlejší efekty do event handlerů (Rule #1)
- •Kdy patří vedlejší efekty do useEffect pro synchronizaci (Rule #2)
- •Jak použít jednoduchou rozhodovací matici pro umístění logiky
Kořen většiny těchto bolestí hlavy je téměř vždy stejný: špatná práce s vedlejšími efekty. Dobrá zpráva je, že si nemusíte pamatovat všechny nuance lifecycle metod – stačí jednoduchý mentální model se třemi pravidly.
Tento článek je praktický, bez zbytečného žargonu: pomůže vám dát každý kus logiky na správné místo tak, aby vaše komponenty byly rychlé, předvídatelné a bezpečné z pohledu hydration.
Základ: v = f(s)
Abychom pochopili, kam vedlejší efekty patří, musíme si ujasnit, co je to vlastně React komponenta. V jádru React následuje jednoduchou matematickou myšlenku:
view = f(state)Vaše komponenta je funkce. Jako vstup bere state (a props) a vrací popis UI jako výstup. Jinými slovy, vaše View je funkcí vašeho stavu: v = f(s).
Vedlejší efekt je všechno, co se děje mimo tento čistý výpočet.
- •Výpočet count * 2? To není vedlejší efekt, to je jen matematika.
- •Změna document.title? Vedlejší efekt – měníte prostředí prohlížeče.
- •Načítání dat? Vedlejší efekt – komunikujete se serverem.
- •console.log? Vedlejší efekt – zapisujete do konzole.
Cílem Reactu je udržet proces renderování — výpočet View — čistý a rychlý. Tři následující pravidla existují proto, aby tuto čistotu chránila.
Pravidlo #0: Zlaté pravidlo renderování
Pravidlo: Funkce, která počítá View, musí být čistý výpočet.
Když React volá vaši komponentu, očekává popis UI – nic víc. Tělo komponenty je posvátné místo: patří sem jen čisté výpočty.
Častou chybou je dát vedlejší efekty přímo do těla funkce:
function UserProfile({ name }) {
// ❌ VIOLATION: Modifying an external system during render
document.title = `Profile: ${name}`
return <h1>Hello, {name}</h1>
}Proč je to problém
- •React volá komponentu mnohokrát — když se renderuje rodič, změní state nebo jen kvůli interním kontrolám. Spouštění vedlejších efektů v tomto místě render zpomaluje.
- •Rozbíjí server-side rendering (SSR): na serveru neexistuje document, takže tento kód spadne.
- •Chování se stává nepředvídatelným, protože ztrácíte kontrolu nad tím, kdy se efekt spouští.
Oprava: nikdy nedávejte vedlejší efekty do top‑levelu komponenty. Udržte render čistý; v Pravidlech #1 a #2 uvidíme, kam tuto logiku přesunout.
Pravidlo #1: Uživatelské akce patří do event handlerů
Pravidlo: Pokud je vedlejší efekt spuštěn konkrétní událostí (click, submit, psaní…), patří do event handleru.
Zní to samozřejmě, ale jde o jedno z nejčastěji porušovaných pravidel. Typickým anti‑vzorem je používat kombinaci state + useEffect jako vlastní event systém.
Anti‑vzor
Představte si, že chcete poslat analytiku, když uživatel klikne na notifikační badge:
function NotificationBadge() {
const [count, setCount] = useState(0)
const [clicked, setClicked] = useState(false)
// ❌ VIOLATION: Using state & effect for a simple action
useEffect(() => {
if (clicked) {
sendAnalytics("badge_clicked")
setClicked(false) // Resetting state? It's getting messy.
}
}, [clicked])
return (
<button
onClick={() => {
setCount(0)
setClicked(true)
}}
>
Notifications
</button>
)
}Skutečnou příčinou vedlejšího efektu je kliknutí uživatele. Efekt je ale navázaný na kus state, což přináší zbytečné rendery i složitost.
Oprava
function NotificationBadge() {
const [count, setCount] = useState(0)
function handleClick() {
// 1. Update State (UI Logic)
setCount(0)
// 2. Run Side Effect (Business Logic) ✅
sendAnalytics("badge_clicked")
}
return <button onClick={handleClick}>Notifications</button>
}- •React ani neví, že k vedlejšímu efektu došlo – vidí jen aktualizaci state.
- •Render zůstává čistý; handler běží až po uživatelské akci.
- •Pro tento scénář nepotřebujete useEffect vůbec.
Pravidlo #2: Synchronizujte pomocí useEffect
Pravidlo: Pokud vedlejší efekt udržuje komponentu v synchronizaci s vnějším systémem, patří do useEffect.
To je jediný skutečný důvod, proč používat useEffect: synchronizace.
Co všechno je „vnější systém“?
- •Databázové nebo API připojení
- •WebSocket nebo jiný subscription
- •DOM prohlížeče (např. document.title)
- •Časovače jako setTimeout nebo setInterval
Pokud chcete, aby vaše komponenta zůstala sladěná s jedním z těchto systémů po dobu, kdy je na obrazovce, je useEffect správný nástroj.
Příklad: document.title
Vraťme se k příkladu s document.title, tentokrát implementovanému správně se zaměřením na synchronizaci:
function NotificationBadge({ count }) {
// ✅ CORRECT: We are synchronizing the DOM with our State
useEffect(() => {
document.title = `(${count}) New Messages`
return () => {
document.title = "React App"
}
}, [count])
return <div className="badge">{count}</div>
}Nepřemýšlejte o dependency array jako o „kdy se tento kód spustí“. Myslete na něj jako na „jaká data efekt používá k synchronizaci“.
Když se count změní, předchozí synchronizace už neplatí. React ji zruší a efekt znovu spustí, aby vnější systém uvedl do souladu s novým stavem.
Rozhodovací matice: Kam tato logika patří?
Příště, až budete psát komponentu a nebudete si jistí, kam logiku umístit, projděte si tento jednoduchý rozhodovací strom:
- Je to jen výpočet View?
Pokud ano, patří to přímo do těla komponenty. To je logika renderování. (Pravidlo #0)
- Spustila to konkrétní uživatelská nebo systémová událost (kliknutí, submit, stisk klávesy…)?
Pokud ano, patří to do event handleru. To je logika akce. (Pravidlo #1)
- Potřebuji udržovat komponentu v čase v synchronizaci s vnějším systémem?
Pokud ano, patří to do useEffect. To je synchronizační logika. (Pravidlo #2)
Pokud vaše logika zjevně nezapadá do žádné z těchto kategorií, zkuste úlohu zjednodušit. Většina reálných bugů kolem vedlejších efektů vzniká tím, že se tyto tři oblasti smíchají dohromady.
Shrnutí
- •React komponenty jsou čisté funkce z props/state do View: v = f(s).
- •Tělo komponenty musí zůstat čisté – žádné vedlejší efekty. (Pravidlo #0)
- •Vedlejší efekty spuštěné konkrétní událostí patří do event handlerů. (Pravidlo #1)
- •useEffect používejte pouze pro synchronizaci s vnějšími systémy v čase. (Pravidlo #2)
Jakmile si tato tři pravidla osvojíte, 99 % práce s vedlejšími efekty se stane přímočarou – a nekonečné smyčky či hydration chyby budou vzácné a snadno opravitelné.