Kódím.cz
3

TypeScript pomalu

Doplňková lekce na projití základů TypeScriptu.

Stav a události v Reactu

V komponentách často vytváříme interní stav pomocí useState. Potřebujeme nastavit, jakého typu bude hodnota, která bude ve stavu uložená.

Pokud jde o základní datové typy, typ se sám odvodí z výchozí hodnoty a my nemusíme nic dělat:

import {useState} from 'react';

export const MyComponent = () => {
  // count má typ number, protože hodnota 0 je number
  const [count, setCount] = useState(0);

  // name má typ string, protože 'Alena' ej string
  const [name, setName] = useState('Alena');
}

Pokud ale potřebujeme do stavu ukládat například objekt, vytvoříme interface a potom tento interface podstrčíme do useState jako typ hodnoty, která tam bude uložená:

import {useState} from 'react';

export interface User {
  name: string;
  age: number;
  hasDog: boolean;
}

export const MyComponent = () => {
  const [user, setUser] = useState<User>({
    name: 'Alena',
    age: 27,
    hasDog: true,
  });
}

Události

Když reagujeme na události (např. odeslání formuláře, klik na odkaz, stisk klávesy), často potřebujeme v obslužné funkci použít tzv. eventObject. Ten má pro každý typ události jinou podobu a a bude obsahovat trochu jiné vlastnosti, když šlo o událost kliknutí na tlačítko (onClick), a jiné vlastnosti, když šlo o událost změna hodnoty formulářového pole (onChange).

Potřebuje-li naše obslužná funkce použít event object, musíme správně nastavit jeho typ, aby TypeScript věděl, jaké vlastnosti v objektu má očekávat.

Kliknutí na tlačítko

function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
  console.log("Kliknuto!", e.clientX, e.clientY);
}

return <button onClick={handleClick}>Klikni</button>;

Změna formulářového pole

function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
  console.log(e.target.value);
}

return <input onChange={handleChange} />;

Pro prvek <textarea> by to bylo React.ChangeEvent<HTMLTextAreaElement> atd.

Odeslání formuláře

function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
  e.preventDefault();
  console.log("Formulář odeslán");
}

return <form onSubmit={handleSubmit}>...</form>;

Nejčastější události pro běžné elementy

Prvek Událost Typ
form onSubmit React.FormEvent<HTMLFormElement>
input onChange React.ChangeEvent<HTMLInputElement>
textarea onChange React.ChangeEvent<HTMLTextAreaElement>
select onChange React.ChangeEvent<HTMLSelectElement>
button onClick React.MouseEvent<HTMLButtonElement>
div onClick React.MouseEvent<HTMLDivElement>
a onClick React.MouseEvent<HTMLAnchorElement>

Jak zjistit, jakého typu je událost

Můžeš hledat na Googlu nebo se zeptat ChatuGPT. Nejjednodušší ale je, nechat si napovědět přímo v editoru. Stačí do události napsat anonymní funkci, která přijímá parametr e, a pak se na něj myší postavit. VS Code ti ukáže nápovědu TypeScriptu, kde bude uvedeno, jakého typu event být.

Například chci reagovat na kliknutí na <div>:

export const ClickableDiv = () => {
  return (
    <div onClick={(e) => {}}> Klikni na mě</div>
  )
}

Když najedu myší na e, VS Code mi řekne, že e je typu React.MouseEvent<HTMLDivElement>.

Na začátku to vypadá složitě, ale časem zjistíš, že se typ skládá ze dvou částí. První 48st určuje typ událostia nejčastěji to bude FormEvent, ChangeEvent, MouseEvent a KeyboardEvent. Druhá část je pak uvedená ve špičatých závorkách a představuje prvek, na kterém k události dochází - např. HTMLDivElement, HTMLInputElement, HTMLButtonAlement a podobně.

Složené typy

Občas se nám stane, že potřebujeme volat jednu funkci, jako reakci na událost u několika různých formulářových prvků.

V TypeSriptu existuje symbol svislítka |, který můžeme použít pro spojení více typů (tzv. union type).

My už jsme jeho použití viděli, když jsme definovali typ, který může obsahovat pouze určité hodnoty, např.:

type Direction = 'sever' | 'jih' | 'východ' | 'západ';

Svislítko slouží jako nebo a říká, že v Direction může být sever nebo jih nebo východ nebo západ.

Stejně ho můžeme použít i v případě naší funkce, která má reagovat na událost onChange na prvku <input> nebo <textarea>.

const onChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
  // kód funkce
}