5

Formulářové prvky, efekty

Zapojíme do našich React aplikací formulářové prvky a ukážeme si jak pomocí efektů volat API.

Díky tomu, že jsem se v minulé lekci naučili pracovat se stavem, otvírají se nám v Reactu mnohé nové možnosti.

Formulářové prvky

Formulářové prvky jako textová polížka, zaškrtávací tlačítka apod. jsou jedním z hlavních způsobů, jak získat vstup od uživatele. V čístém JavaScritpu jsme zvyklí získávat hodnoty z těchto prvků tak, že je vybereme pomocí querySelector a použijeme například vlastnost value.

const inputElm = document.querySelector('input');
const value = inputElm.value;

V Reactu však k DOM elementům na stránce přístup nemáme. Hodnotu uvnitř textového políčka si tak musíme uložit do stavu.

Představme si jednoduchou komponentu, kde uživatel zadá svůj věk.

const AgeField = () => {
  return (
    <label>
      Zadej svůj věk:
      <input type="text" />
    </label>
  );
};

Hodnotu uvnitř elementu input si chceme uložit do stavu pokaždé, když dojde k její změně. Vytvoříme si proto stav age a budeme jej měnit v reakci na událost onChange.

const AgeField = () => {
  const [age, setAge] = useState(null);

  return (
    <label>
      Zadej svůj věk:
      <input type="text" onChange={(e) => setAge(e.target.value)} />
    </label>
  );
};

Tímto postupem se snažíme provázat obsah políčka s hodnotou ve stavu. Kdykoliv uživatel obsah políčka změní, my na to zareagujeme změnou stavu age. Tomuto principu se anglicky říká data binding.

Pozor však, že náš data binding zatím funguje pouze jedním směrem, tedy změna políčkazměna stavu. Pokud se z nějakého důvodu změní hodnota ve stavu age, obsah políčka se zatím neaktualizuje.

Obousměrný data binding

To, co jsme viděli v ukázce výše bychom mohli nazvat one-way (jednosměrný) data binding. V praxi však téměř vždy budeme chtít takzvaný two-way (obousměrný) data binding. Ten zařídíme jednoduše tak, že hodnotu ve stavu vždy nastavíme jako hodnotu políčka.

const AgeField = () => {
  const [age, setAge] = useState(null);

  return (
    <label>
      Zadej svůj věk:
      <input type="text" value={age} onChange={(e) => setAge(e.target.value)} />
    </label>
  );
};

Takto zajistíme provázanost i druhým směrem, tedy změna stavuzměna políčka.

Cvičení: Formulářové prvky

1

Registrace

to dáš
  1. Založte si novou React aplikaci dle klasického postupu.

  2. Vytvořte komponentu App s jednoduchým textovým políčkem dle následujícího vzoru.

    const App = () => {
      const handleSubmit = (e) => {
        e.preventDefault();
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <label>
            Uživatelské jméno:
            <input type="text" />
          </label>
          <button type="submit">Registrovat</button>
        </form>
      );
    };
    
  3. Na políčko přidejte událost onChange. V reakci na událost do konzole vypište obsah políčka pomocí vlastnosti target.value. Vyzkoušejte, že když do políčka píšete, v konzoli vidíte každou změnu jeho hodnoty.

  4. Uvnitř komponenty App vytvořte stav userName s výchozí hodnotou prázdný řetězec. Vytvořte obousměrný (two-way) data binding mezi textovým políčkem a stavem userName.

  5. V reakci na událost onSubmit do konzole vypište jméno uživatele uložené ve stavu userName.

  6. Na stránku vložte div se zprávou

    Uživatelské jméno je povinný údaj
    

    Tato zpráva všech bude vidět pouze pokud je ve stavu userName prázdný řetězec. V opačném případě tento div skryjte pomocí display: none.

  7. Vzpomeňte si na vlastnost disabled a zařiďte, aby registrační tlačítko bylo dostupné pouze v případě, že ve stavu userName není prázdný řetězec.

2

Výběr země

to dáš

Pokračujte v předchozím cvičení.

  1. Přidejte do vašeho formuláře rozbalovací nabídku select, která bude sloužit k výběru země, ze které uživatel pochází.

    <label>
      Země původu:
      <select>
        <option value="Chorvatsko">Chorvatsko</option>
        <option value="Česká republika">Česká republika</option>
        <option value="Polsko">Polsko</option>
        <option value="Slovenská republika">Slovenská republika</option>
      </select>
    </label>
    
  2. Vytvořte stav country, který bude sloužit k uložení hodnoty z vaší nabídky. Výchozí hodnotu stavu nastavte na Česká republika.

  3. Pomocí události onChange zařiďte one-way data binding mezi nabídkou select a stavem country.

  4. Zařiďte two-way data binding mezi nabídkou select a stavem country tak, aby nabídka zobrazovala výchozí hodnotu uloženou ve stavu.

  5. Zprávu vypisovanou do konzole po úspěšné registraci změňte na

    Registrován nový uživatel jaroslav ze země Polsko
    

    Ve zprávě zobrazte zemi, kteoru si uživatel při registraci vybral.

3

Podmínky registrace

to dáš

Pokračujte v předchozím cvičení.

  1. Přidejte do vašeho formuláře zaškrtávací políčko označené textem
    Souhlasím s obchodními podmínkami
    
  2. Zařiďte, aby se uživatel mohl registrovat pouze v případě, že zaškrtnul souhlas s obdchodními podmínkami. K tomu bude potřeba vyrobit další stav, například termsAccepted, který bude se zaškrtávacím políčkem provázený.

Efekty

V mírně komplikovanějších React aplikacích brzy narazíme na potřebu zareagovat na určité situace, které nastávají během vykreslování (renderování) komponenty. Budeme chtít například spustit nějaký kód ve chvíli, kdy se komponenta poprvé objeví na stránce. Čas od času také budeme chtít v komponentě provést něco ve chvíli, kdy se změní hodnota v props nebo ve stavu. K tomuto nám v Reactu slouží takzvané efekty effects .

Efekty jsou v podstatě velmi podobné událostem. Ve chvíli, kdy uvnitř komponenty něco nastane, budeme chtít zavolat naši funkci. Jako příklad si vyrobíme jednoduchou aplikaci, která řiká, kdo má zrovna svátek.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

const App = () => {
  return (
    <>
      <h1>Svátky</h1>
      <div className="nameday">Svátek má Jiří</div>
    </>
  );
};

render(<App />, document.querySelector('#app'));

Pokud bychom chtěli spustit kousek kódu ve chvíli, kdy se naše komponenta App objeví na stránce, použijeme funkci useEffect a té předáme námi vytvořenou funkci.

import React, { useEffect } from 'react';
import { render } from 'react-dom';
import './index.html';

const App = () => {
  useEffect(() => console.log('jsem tady'), []);

  return (
    <>
      <h1>Svátky</h1>
      <div className="nameday">Svátek má Jiří</div>
    </>
  );
};

render(<App />, document.querySelector('#app'));

Funkce useEffect má dva parametry. Prvním je funkce, která se má zavolat a druhý parametr říká, za jakých okolností se má naše funkce volat. Prázdné pole [] znamená, že se efekt spustí pouze ve chvíli, kdy se komponenta poprvé objeví na stránce.

Efekty a volání API

Pokud chceme v naší aplikaci zobrazovat data z nějakého API, musíme si tato data stáhnout pomocí nám již známé funkce fetch. Tuto funkci je nejlepší zavolat právě ve chvíli, kdy se naše komponenta poprvé objeví na stránce.

Naše poslední aplikace zatím zobrazovala, že svátek má Jiří. To je však pravda pouze jeden den v roce. Pojďme aplikace vylepšit tak, aby si stáhla aktuální jméno z API.

import React, { useState, useEffect } from 'react';
import { render } from 'react-dom';
import './index.html';

const App = () => {
  const [name, setName] = useState('');

  useEffect(() => {
    fetch('https://api.abalin.net/today?country=cz')
      .then((resp) => resp.json())
      .then((json) => setName(json.data.namedays.cz)
  }, []);

  return (
    <>
      <h1>Svátky</h1>
      <div className="nameday">Svátek má {name}</div>
    </>
  );
};

render(<App />, document.querySelector('#app'));

V tomto případě jsme si do stavu ukládali pouze obyčejný řetězec. Naše data však budou často zobrazovat seznamy, takže budeme chtít mít ve stavu uložené nějaké pole.

https://worldtimeapi.org/api/timezone

Cvičení: Efekty a volání API

4

Pražský čas

to dáš
  1. Založte si novou React aplikaci podle klasického postupu.

  2. Uvnitř komponenty App vytvořte jednoduchý efekt, který se spustí pří prvním zobrazení komponenty. Uvnitř tohoto efektu zavolejte funkci alert a zobrazte vyskakovcí okno s nějakou zprávou.

  3. Přidejte do vaší komponenty stav datetime, jehož výchozí hodnota bude prázdný řetězec. Ve vašem efektu smažte volání alert a uložte do stavu nějaký čas jako řetězec ve formátu

    '2020-11-13T22:46';
    

    Zobrazte váš čas někde na stránce a vyzkoušejte, že váš efekt správně nastaví stav při prvním zobrazení komponenty.

  4. Upravte váš efekt tak, aby pomocí volání fetch získal aktuální datum a čas pro časovou zónu Europe/Prague. Hodnotu získáte na API endpointu

    https://worldtimeapi.org/api/timezone/Europe/Prague
    

    pod položkou datetime. Získanou hodnotu uložte do stavu a vyzkoušejte, že vaše aplikace funguje.

5

Výběr zóny

to dáš

Pokračujte v předchozím příkladu.

  1. Vložte do stránky formulář, ze kterého si uživatel může vybrat časovou zónu. Uvnitř formuláře použijte následující select.
    <select>
      <option value="America/New_York">New York</option>
      <option value="Europe/London">Londýn</option>
      <option value="Europe/Moscow">Moskva</option>
      <option value="Europe/Prague">Praha</option>
      <option value="Asia/Hong_Kong">Hong Kong</option>
      <option value="Asia/Jerusalem">Jeruzalém</option>
    </select>
    
  2. Vytvořte stav timezone a funkci handleTimezoneChange, která propojí stav s hodnotou uvnitř prvku select. Jako výchozí hodnotu pro tento stav zvolte Europe/Prague.
  3. Zařiďte, aby se váš efekt volal při každé změně stavu timezone. Uvnitř efektu zkunstruujte URL pro váš dotaz tak, aby server poslal data pro uživatelem vybranou časovou zónu.
  4. Vaše aplikace by měla fungovat tak, že když uživatel vybere z nabídky časovou zónu, rovnou se mu na stránce ukáže aktuální čas v této zóně.