Lekce 1.5

Mastering Events

Building interactive applications requires one fundamental capability: responding to user actions. Clicks, keyboard presses, text input, copying, dragging — modern interfaces depend on events.

Co se naučíte
  • How event handlers work in React
  • The difference between function references and invocations
  • Why event handlers belong inside components
  • How to access event information
  • Building interactive applications with events

React systém událostí to dělá přímočarým, ale plné pochopení toho, jak handlery fungují, jak se předávají a jak je React volá, z vás udělá mnohem sebevědomějšího vývojáře.

Event Handlery začínají jako jednoduché funkce

Představte si, že chceme tlačítko, které při kliknutí vypíše zprávu. Začněme s UI:

jsx
export default function LoggerButton() {
  return <button>Log Something</button>
}

Nyní vytvořte event handler:

javascript
const handleClick = () => {
  console.log("Button clicked")
}

A připojte to pomocí vestavěné prop onClick:

jsx
export default function LoggerButton() {
  const handleClick = () => {
    console.log("Button clicked")
  }

  return <button onClick={handleClick}>Log Something</button>
}

Tento příklad demonstruje dva univerzální vzory:

  • Zapouzdříte logiku do vyhrazených event handler funkcí
  • Předáváte referenci na funkci, ne výsledek

Reference vs. Volání: Nejčastější chyba začátečníků

Tyto vypadají podobně, ale chovají se velmi odlišně:

jsx
<button onClick={handleClick}>Reference</button>
<button onClick={handleClick()}>Invocation</button>
  • Předání reference (handleClick) → React to může později zavolat
  • Předání volání (handleClick()) → JavaScript to okamžitě zavolá a předá vrácenou hodnotu do onClick

Většinu času verze s voláním rozbije vaše UI, protože React obdrží něco jako undefined místo funkce.

To platí pro všechny props, které očekávají funkce, nejen pro event handlery.

Proč event handlery žijí uvnitř komponent

Zde je malé tlačítko, které zobrazí alert na základě prop:

jsx
function AlertButton({ text }) {
  const handleClick = () => alert(text)

  return <button onClick={handleClick}>Show Alert</button>
}

Protože je handler definován uvnitř komponenty, automaticky získává přístup k props, stavu a čemukoli jinému v rozsahu.

Pokud přesuneme handler ven:

jsx
function handleClick() {
  alert(text) // ❌ ReferenceError
}

function AlertButton({ text }) {
  return <button onClick={handleClick}>Show Alert</button>
}

Ztratíte přístup k text. React vývojáři se rychle naučí, že event handlery patří dovnitř komponent, pokud není velmi explicitní důvod k výkonu, proč ne.

"Ale React převykresluje — nevytváří to funkce znovu?"

Ano. A obvykle to není důležité.

JavaScript enginy jsou extrémně optimalizované na alokaci a uvolňování funkcí. Typické React vykreslení vytváří desítky z nich; to je normální a očekávané.

Pouze v extrémně náročných interakčních scénářích začnete řešit stabilní reference — ale pak použijete useCallback nebo memoizaci, což patří do pokročilého tématu.

Přístup k informacím o události

Každý React event handler obdrží Synthetic Event — React cross-browser wrapper kolem nativních událostí prohlížeče.

Například:

javascript
function handleChange(e) {
  console.log(e.target.value)
  console.log(e.timeStamp)
}

Užitečné vlastnosti zahrnují:

  • targetprvek, který spustil událost
  • currentTargetprvek, ke kterému je handler vázán
  • timeStampkdy se událost stala
  • typetyp události, např. "click"

Pojďme postavit něco praktického, co spoléhá na data události.

Skutečný příklad: Vytvořte mini-hru "Fast Typer"

Cíl:

Zobrazte uživateli náhodné slovo. Musí ho napsat a stisknout Enter do 3 sekund.

Krok 1: Utility a UI

javascript
const WORDS = ["react", "javascript", "hooks", "state", "props"]

function getRandomWord() {
  return WORDS[Math.floor(Math.random() * WORDS.length)]
}

Kostra komponenty:

jsx
export default function FastTyper() {
  const [word, setWord] = React.useState(() => getRandomWord())
  const [startTime, setStartTime] = React.useState(() => Date.now())

  return (
    <div>
      <h2>Type this word:</h2>
      <strong>{word}</strong>
      <input placeholder="Start typing..." />
      <button>Reset</button>
    </div>
  )
}

Krok 2: Zpracování psaní

Musíme vědět:

  • Co uživatel napsal (e.target.value)
  • Kdy to napsal (Date.now())
javascript
function handleKeyDown(e) {
  if (e.key !== "Enter") return

  const elapsed = Date.now() - startTime
  const isCorrect = e.target.value.trim() === word
  if (!isCorrect) {
    alert("Incorrect word!")
  } else if (elapsed > 3000) {
    alert("Too slow!")
  } else {
    alert("Winner!")
  }
}

Připojte handler:

jsx
<input onKeyDown={handleKeyDown} placeholder="Start typing..." />

Krok 3: Reset Handler

javascript
function handleReset() {
  setWord(getRandomWord())
  setStartTime(Date.now())
}

Finální JSX:

jsx
<button onClick={handleReset}>Reset</button>

Tento příklad demonstruje:

  • Předávání event handlerů
  • Čtení dat události
  • Porovnávání časových razítek
  • Vazba handlerů v JSX

Kompletní komponenta pro referenci

jsx
const WORDS = ["react", "javascript", "hooks", "state", "props"]
const getRandomWord = () => WORDS[Math.floor(Math.random() * WORDS.length)]

export default function FastTyper() {
  const [word, setWord] = React.useState(() => getRandomWord())
  const [startTime, setStartTime] = React.useState(() => Date.now())

  const handleKeyDown = (e) => {
    if (e.key !== "Enter") return
    
    const elapsed = Date.now() - startTime
    const isCorrect = e.target.value.trim() === word
    if (!isCorrect) return alert("Incorrect word!")
    if (elapsed > 3000) return alert("Too slow!")
    alert("Winner!")
  }

  const handleReset = () => {
    setWord(getRandomWord())
    setStartTime(Date.now())
  }

  return (
    <div>
      <h2>Type this word:</h2>
      <strong>{word}</strong>
      <input
        autoFocus
        placeholder="Start typing…"
        onKeyDown={handleKeyDown}
      />
      <button onClick={handleReset}>Reset</button>
    </div>
  )
}

Všechny React události k dispozici

React podporuje širokou škálu událostí:

(click, copy, drag, keydown, blur, submit, wheel, touchstart, animationend, atd.)

Místo jejich znovu výpisu si zapamatujte pravidlo:

Pokud to prohlížeč podporuje, React to pravděpodobně také podporuje — s camelCase pojmenováním

Shrnutí

Události jsou srdcem interaktivního vývoje UI. Jakmile pochopíte:

  • předávání referencí
  • umístění handlerů uvnitř komponent
  • využití lexikálního rozsahu
  • a použití Synthetic Event objektu

…můžete implementovat cokoli od jednoduchých kliknutí na tlačítka až po plnohodnotné interaktivní hry a aplikace.