Lekce 1.7

Porozumění renderování

React se dá shrnout do jedné rovnice: vaše UI je čistá funkce vašeho stavu. Přesto je otázka „kdy přesně React renderuje?“ jednou z nejčastějších příčin zmatku – i u zkušených vývojářů.

Co se naučíte
  • Co přesně znamená „renderování“ v Reactu
  • Kdy React renderuje a re-renderuje komponenty
  • Jak fungují snapshoty props, state a event handlerů
  • Kdy React re-render přeskočí
  • Jak funguje batchování aktualizací a proč na něm záleží
  • Proč se znovu renderují i podkomponenty a jak to řídit

Mentální model Reactu můžeme zhuštit do jediné rovnice:

text
v = f(s)

Vaše UI (v) je výsledkem volání funkce (f) s komponentním stavem (s). To ale vyvolává důležitou otázku: kdy přesně React volá tuto funkci?

Co vlastně znamená renderování

Renderování je proces, při kterém React zavolá vaši komponentní funkci, aby vytvořil popis UI.

  • React vezme snapshot vaší komponenty v určitém čase
  • Tento snapshot obsahuje props, state, event handlery a JSX
  • React použije JSX výstup k aktualizaci skutečného DOMu
jsx
import { createRoot } from "react-dom/client"
import Dashboard from "./Dashboard"

const el = document.getElementById("root")
const root = createRoot(el)

root.render(<Dashboard />)

Kdy React re-renderuje?

React re-renderuje komponentu pouze tehdy, když se změní její state.

Když se změní state rodičovské komponenty, React re-renderuje rodiče — a poté ve výchozím nastavení všechny jeho potomky.

jsx
function Spark() {
  console.log("Spark rendered")
  return <span></span>
}

export default function Header() {
  const [count, setCount] = React.useState(0)

  return (
    <h1>
      Greetings <Spark />{" "}
      <button onClick={() => setCount(c => c + 1)}>Update</button>
    </h1>
  )
}

Snapshoty a event handlery

Když se spustí event handler, vidí props a state ze snapshotu renderu, ve kterém byl vytvořen.

jsx
export default function Lamp() {
  const [mode, setMode] = React.useState("off")

  function toggle() {
    setMode("on")
    console.log("Current mode inside handler:", mode)
  }

  return <button onClick={toggle}>{mode}</button>
}

Při prvním kliknutí snapshot říká mode = "off", takže konzole vypíše "off", i když voláte setMode("on"). Při dalším renderu se snapshot aktualizuje.

Kdy React re-render přeskočí

Pokud nastavíte state na úplně stejnou hodnotu jako předtím, React pro danou komponentu re-render přeskočí.

jsx
export default function Counter() {
  const [n, setN] = React.useState(5)

  function reset() {
    setN(5) // same as existing state
  }

  return <button onClick={reset}>{n}</button>
}

Jak React batchuje aktualizace state

Uvnitř jednoho event handleru React batchuje aktualizace state a aplikuje je dohromady až po dokončení handleru.

javascript
function handle() {
  setLevel(10)
  setLevel(20)
  setLevel(30)
}

Konečná hodnota bude 30, ne 10 → 20 → 30. S funkcionálními aktualizacemi může každá aktualizace vidět nejnovější mezihodnotu:

javascript
function handle() {
  setLevel(1)            // Intermediate: 1
  setLevel(l => l + 4)   // Intermediate: 5
  setLevel(100)          // Overwrites: 100
  setLevel(l => l + 6)   // Final: 106
}

StrictMode a dvojité renderování

V režimu vývoje Reactův StrictMode záměrně renderuje komponenty dvakrát, aby odhalil nečistou logiku a nebezpečné vedlejší efekty.

jsx
import { StrictMode } from "react"

root.render(
  <StrictMode>
    <Dashboard />
  </StrictMode>
)

Toto chování se děje pouze v režimu vývoje a v produkčních buildch zmizí.

Shrnutí

  • React re-renderuje, když se změní state
  • Event handlery vždy vidí snapshot z renderu, ve kterém byly definovány
  • React batchuje aktualizace state a aplikuje je najednou
  • Rodiče se re-renderují → děti se re-renderují, pokud nepoužijete memoizaci
  • StrictMode provádí dvojité renderování pouze v režimu vývoje

S tímto mentálním modelem se většina otázek ohledně renderování v Reactu stává předvídatelnou — i ve velkých aplikacích.