Lekce 10. - React Hooks - zpracování formulářů

15.04.2021 Programování #react #programování

Rozpracování problematiky formulářů v Reactu pomocí React Hooks


Způsob, jakým zpracováváme vstup formuláře v Reactu, je ve srovnání s běžným HTML trochu odlišný.

V HTML si vstupy formuláře zachovávají svůj vnitřní stav (tj. vstupní hodnotu) a jsou udržovány DOMem. Ale v Reactu za zpracování vstupů z formulářů zodpovídáme my.

Ukážeme si, jak lze s těmito vstupními poli snadno zacházet. Pokryjeme běžné typy formulářů, jako je checkbox, text, listbox, rádio, range a textová plocha.

reagovat formou projektu

Jak vidíte, vstupní hodnoty získáváme v reálném čase (a při každém stisknutí klávesy pro zadávání textu). To je jedna z krás Reactu.

Pro vysvětlení principu práce s formuláři, vytvořme jednoduchý projekt React. Přesuňte se do adresáře pro instalaci nové aplikace a spusťte z terminálu následující příkaz:

npx create-react-app react-form-handling

Příkaz vytvoří složku ve zvoleném adresáři projektu nazvanou react-form-handling.

Otevřete složku pomocí oblíbeného editoru kódu a spusťte vývojový server:

npm start

Váš projekt by měl být spuštěn na portu 3000.

Začněme zobrazením jednoduchého textového pole pro zadávání textu. Takže jděte do souboru src/App.js a nahraďte kód tímto:

import React from "react"
import "./App.css"

function App() {
  return (
    <div>
      <h1>React Form Handling</h1>
      <form>
        <label>
          First Name: <input type="text" />
        </label>
      </form>
    </div>
  )
}

export default App

Uložte soubor a zkontrolujte rozhraní.

Měl by se vykreslit jednoduchý prvek form zobrazující textové pole pro zadávání textu. Nic zvláštního. Je to jako náš běžný vstup HTML. Abychom ale zvládli tento vstup v React, budeme muset porozumět konceptu řízeného vstupu.

Nekontrolovaný a kontrolovaný vstup

V tuto chvíli si tento prvek input, stejně jako čistá forma HTML, udržuje svůj vnitřní stav. Proto do něj můžeme ve výchozím nastavení něco napsat. V tomto případě nazýváme tento typ vstupu nekontrolovaným vstupem.

V React je odpovědností komponenty vykreslující formulář kontrola stavu vstupu. Tímto způsobem by vstup již neposlouchal svůj vnitřní stav, ale stav deklarovaný v jeho komponentě. Tímto způsobem děláme stav komponenty jediným zdrojem pravdy.

Pokud máte tento typ vstupu, máte řízený vstup.

Jak to funguje?

V závislosti na typu vaší komponenty uložíte vstupní data ve stavu komponenty. Zde budeme používat React Hook ke správě dat formuláře. Přístup je však stejný, pokud používáte komponentu založenou na třídě. Jediné, co musíte udělat, je deklarovat objekt state, kde by žila vaše data.

Odtud nastavíte logiku, která poslouchá změny ve vstupu a ovládá jej (tj. Aktualizuje stav) pomocí události onChange. Tímto způsobem vždy získáte aktuální hodnotu, jak uvidíte za okamžik.

Prvním krokem je, aby stav spravoval vstup uživatele. Pokračujte a aktualizujte soubor src/App.jstak, aby obsahoval stav.

import React, { useState } from "react"
import "./App.css"

function App() {
  const [fname, setFname] = useState("")

  return (
    <div>
      <h1>React Form Handling</h1>
      <form>
        <label>
          First Name: <input type="text" value={fname} />
        </label>
      </form>
      <h5>First name: {fname}</h5>
    </div>
  )
}

export default App

Nyní, abychom z vstupního pole vytvořili řízený vstup, přiřadili jsme k vlastnosti value stavovou proměnnou (která obsahuje výchozí prázdný řetězec).

Pokud se nyní pokusíte do pole pro zadávání textu cokoli napsat, nic se nestane. Je to proto, že vlastnosti value je přiřazena stavová proměnná, jejíž hodnota je nastavena na prázdný řetězec. A to je vynuceno na vstupu.

To je dobré, protože nyní máme úplnou kontrolu nad vstupním stavem. Pojďme to aktualizovat. Aktualizujte kód tak, aby zahrnoval obslužnou rutinu události onChange.

import React, { useState } from "react"
import "./App.css"

function App() {
  const [fname, setFname] = useState("")

  const handleChange = e => {
    setFname(e.target.value)
  }

  return (
    <div>
      <h1>React Form Handling</h1>
      <form>
        <label>
          First Name:{" "}
          <input type="text" value={fname} onChange={handleChange} />
        </label>
      </form>
      <h5>First name: {fname}</h5>
    </div>
  )
}

export default App

Uložte soubor.

Nyní byste měli být schopni něco napsat do vstupního pole. Jak vidíte níže (v nástrojích React a v pohledu frontendu), získáváme nejaktuálnější hodnotu při každém stisknutí klávesy.

jedno textové pole

Co se děje?

React potřebuje obsluhu onChange, aby sledoval jakékoli změny v poli. Kdykoli do vstupního pole něco napíšete, tato událost onChange se spustí a poté zavolá svou funkci handleChange, která znovu vykreslí stav pomocí funkce setFname.

V této funkci aktualizujeme stavovou proměnnou, fname a při každém stisknutí klávesy jí předáme aktuální hodnotu vstupního pole pomocí e.target.value.

V tomto okamžiku máme řízené vstupní pole, kde je jeho stav řízen jeho komponentou. Toto je nejjednodušší příklad formuláře React.

Přidání více vstupních polí

Ve skutečnosti budete ve své aplikaci React pracovat s více vstupními poli. V tomto příkadu provedeme jednoduchou úpravu nejen funkce obslužné rutiny, ale také prvky input.

Podívejme se na to přidáním dalšího vstupního pole, které zahrnuje příjmení uživatele.

Mohli bychom se rozhodnout nastavit další hook useState pro zadání příjmení. Pak pokračujte a přiřaďte jeho stavovou proměnnou vlastností value. Ale tento přístup bude vyžadovat, abychom definovali jinou funkci obslužné rutiny pro aktualizaci stavu vstupu.

To nechceme. Chceme spravovat celý stav pomocí jedné obslužné funkce.

Takže místo toho, abychom předali jednoduchý řetězec v hooku useState, jak ho máme v tuto chvíli, budeme předávat objekt obsahující všechna související stavová data.

V souboru src/App.js aktualizujme komponentu formuláře:

import React, { useState } from "react"
import "./App.css"

function App() {
  const [state, setState] = useState({
    fname: "",
    lname: "",
  })

  const handleChange = e => {
    setState({
      ...state,
      [e.target.name]: e.target.value,
    })
  }

  return (
    <div>
      <h1>React Form Handling</h1>
      <form>
        <label>
          First Name:{" "}
          <input
            type="text"
            name="fname"
            value={state.fname}
            onChange={handleChange}
          />
        </label>{" "}
        <label>
          Last Name:{" "}
          <input
            type="text"
            name="lname"
            value={state.lname}
            onChange={handleChange}
          />
        </label>
      </form>
      <h5>
        Name: {state.fname} {state.lname}
      </h5>
    </div>
  )
}

export default App

Uložte soubor a otestujte zadávací pole.

více textových polí

Co se děje?

Nejprve si všimněte významné změny v kódu. Začali jsme úpravou hooku useState tak, aby obsahoval další vstupní data. Odtamtud máme přístup ke křestnímu jménu state.fname a příjmení a state.lname podle toho, jak jsou použity ve vlastnosti value jejich příslušného prvku input.

V těchto input prvcích jsme přidali vlastnost name, která obsahuje také jejich příslušný název stavu (tj. fname a lname). Tohle je velmi důležité.

Nyní se zaměřme na funkci handleChange. Zde používáme funkci setState k aktualizaci stavu vstupů.

const handleChange = e => {
  setState({
    ...state,
    [e.target.name]: e.target.value,
  })
}

V této funkci jednoduše přiřazujeme prvku, na který je cíleno (prostřednictvím [e.target.name]) jejich odpovídající hodnoty.

Například pokud se změní pole pro křestní jméno, fname přidělí se vlastnosti name [e.target.name] takto:

setState({
  fname: e.target.value,
})

Totéž platí pro všechny ostatní vstupní prvky.

Kdykoli seskupíme související data, protože je máme v proměnné stavu, stav vrácený hookem useState nebude sloučen se stavem předané aktualizace. Jinými slovy, useState nespojuje starý a nový stav. Místo toho přepíše celý stav tím

aktuálním.

Chcete-li získat jasnější obrázek, zakomentujte …state ve funkci odkomentujte, abyste měli:

const handleChange = e => {
  setState({
    // ...state,
    [e.target.name]: e.target.value,
  })
}

Uložte soubor ještě jednou a zkuste něco napsat do obou vstupních polí. Uvidíte, že se navzájem přepisují.

Abychom se tomuto scénáři vyhnuli, sloučíme je tak, že rozložíme celý stavový objekt pomocí tří teček před stavem a přepíšeme jeho část.

Nyní, když víte, jak textová pole v Reactu fungují, budeme přidávat další vstupní pole.

Přidání pole TextArea

Na rozdíl od běžného HTML, kde definujeme textovou plochu elementy textarea, v Reactu je textarea definována jako nepárový element, stejně jako prvek input.

React se snaží udržet konzistenci s těmito vstupy. To je dobré, protože můžeme také použít vlastnost value k získání její aktuální hodnoty stavu.

To je jednoduché.

Jak se dalo očekávat, necháme stav spravovat vstup uživatele (tj. Textovou zprávu). Aktualizujte tedy stav tak, aby obsahoval vlastnost message:

const [state, setState] = useState({
  fname: "",
  lname: "",
  message: "",
})

Dále přidejte prvek textarea do příkazu return:

return (
  ...
    <form>
      ...
      <br />
      <label>
        Your Message:{" "}
        <textarea
          name="message"
          value={state.message}
          onChange={handleChange}
        />
      </label>
    </form>
    <h5>
      Name: {state.fname} {state.lname}
    </h5>
    <p>Message: {state.message}</p>
  </div>
);

Vezměte na vědomí prvek value a vlastnost name pro element textarea. Stejně jako u vstupního pole musí být vlastnost name řetězec přiřazený o stejném názvu, co je deklarovaný v objektu stavu.

Uložte soubor a otestujte pole formuláře. Mělo by to fungovat podle očekávání.

ListBox

Neliší se od ostatních formulářových polí. Jako obvykle z něj můžeme udělat řízený vstup tím, že nejprve necháme stavem spravovat vstupní data. Pak přidejte do prvku vlastnost value a nakonec ji aktualizujte pomocí funkce obslužné rutiny onChange (ale v našem případě zde nemusíme nic dělat, protože logiku již máme nastavenou).

A nezapomeňte přidat vlastnost name, která odpovídá názvu ve stavu. Vytvořme tedy rozevírací seznam s možnostmi výběru značek automobilů.

Podle očekávání přidejte novou vlastnost ve stavu. V našem případě je název carBrand.

const [state, setState] = useState({
  ...
  carBrand: "",
});

Poté přidejte prvek select těsně před uzavírací značku </ form >:

return (
  ...
    <form>
      ...
      <br /><br />
      <label>
        Pick your favorite car brand:
        <select
          name="carBrand"
          value={state.carBrand}
          onChange={handleChange}
        >
          <option value="mercedes">Mercedes</option>
          <option value="bmw">BMW</option>
          <option value="maserati">Maserati</option>
          <option value="infinity">Infinity</option>
          <option value="audi">Audi</option>
        </select>
      </label>
    </form>
    <h5>
      Name: {state.fname} {state.lname}
    </h5>
    <h5>My favorite car brand: {state.carBrand}</h5>
    <p>Message: {state.message}</p>
  </div>
);

Uložte soubor a otestujte.

Stále děláme totéž. Vlastnost value na elementu select je kontrolovaný vstup. Prostřednictvím této vlastnosti máme v každém bodě přístup k vybrané možnosti. Pokud chcete zobrazit výchozí položku (například nekonečno) z možnosti výběru, měl by váš stav obsahovat položku takto:

carBrand: "infinity",

Zaškrtávací políčko - checkbox

Na rozdíl od ostatních vstupních polí používá zaškrtávací políčko místo vlastnosti value vlastnost checked (což je logický atribut), protože políčko je buď zaškrtnuto true, nebo ne false.

Nyní, pokud se podíváte na funkci handleChange, uděláme opatření pouze pro vstupy, které mají vlastnost value pomocí e.target.value.

Budeme muset upravit funkci obslužné rutiny tak, aby vyhovovala typu zaškrtávacího políčka. Začněme přidáním nové vlastnosti do stavu. V našem případě to je název isChecked.

const [state, setState] = useState({
  ...
  isChecked: false,
});

Zde přiřadíme booleovskou hodnotu false tak, aby ve výchozím nastavení nebylo pole zaškrtnuto. Dále přidejte zaškrtávací políčko těsně před závěrečnou značku </ form >.

return (
  ...
    <form>
      ...
      <br /><br />
      <label>
        <input
          type="checkbox"
          name="isChecked"
          checked={state.isChecked}
          onChange={handleChange}
        />
{" "}
        Is Checked?
      </label>
    </form>
    <h5>
      Name: {state.fname} {state.lname}
    </h5>
    <h5>My favorite car brand: {state.carBrand}</h5>
    <p>Message: {state.message}</p>
    <h5>Is it checked? : {state.isChecked ? "Yes" : "No"}</h5>
  </div>
);

Nakonec aktualizujeme funkci handleChange, abyste měli:

const handleChange = e => {
  const value = e.target.type === "checkbox" ? e.target.checked : e.target.value
  setState({
    ...state,
    [e.target.name]: value,
  })
}

Pokud soubor uložíte a otestujete políčko, mělo by to fungovat.

Co se stalo?

Jak jsem již zmínil, vlastnost checked nahradí vlastnost value. Stále platí stejná logika.

Prozatím se zaměřme na funkci handleChange.

V této funkci nemůžeme použít dřívější logiku ke správě zaškrtávacího políčka, protože nemá atribut value ale checked. Budete tedy muset upravit, pokud chcete, aby to stejné handleChange spravovalo zaškrtávací políčko.

Dříve jsme se zaměřili pouze na name value ze vstupů z předdefinovaného parametru e (nezapomeňte, že tento parametr obsahuje informace o vstupní akci nebo události).

Jak je vidět na musíme se zaměřit se na vlastnosti type a na atribut checked z tohoto parametru události e. Odtamtud používáme ternární operátor, což je vložený příkaz if ke kontrole typů vstupů a následnému přiřazení jejich odpovídající hodnoty (buď Boolean e.target.checked pro zaškrtávací políčko, nebo e.target.value pro všechny ostatní typy vstupů).

Radio button

Typy vstupů radio buttonů kombinují vstupní text a typ zaškrtávacího políčka. Jinými slovy, používají jak value a tak i checked.

Podívejme se, jak to funguje.

Vytvoříme radio buttony, které uživatelům umožní vybrat pohlaví. Podle očekávání to přidejme do stavu.

const [state, setState] = useState({
  ...
  gender: "",
});

Poté přidejte radio těsně před značku </ form >:

return (
 ...
    <form>
      ...
      <br /><br />
      <label>
        <input
          type="radio"
          name="gender"
          value="male"
          checked={state.gender === "male"}
          onChange={handleChange}
        />
{" "}
        Male
      </label>
      <label>
        <input
          type="radio"
          name="gender"
          value="female"
          checked={state.gender === "female"}
          onChange={handleChange}
        />
{" "}
        Female
      </label>
    </form>
    <h5>
      Name: {state.fname} {state.lname}
    </h5>
    <h5>My favorite car brand: {state.carBrand}</h5>
    <p>Message: {state.message}</p>
    <h5>Is it checked? : {state.isChecked ? "Yes" : "No"}</h5>
    <h5>Gender Selected : {state.gender}</h5>
  </div>
);

Uložte soubor a vyzkoušejte přepínače.

Co se děje?

Jak již víte, jakmile máte stav, který spravuje váš vstup, okamžitě přiřadíte vlastnost state k vlastnosti name. Z HTML byste měli vědět, že skupina rádio buttonů sdílí stejný název. To nám umožňuje vybrat pouze jedno tlačítko najednou.

Všimněte si, že vlastnost value v těchto polích je statická, na rozdíl od textových vstupů, kde její hodnota pochází ze stavu.

A konečně, vlastností checked, říkáme, že pokud je přiřazená podmínka true, měl by být tento přepínač zaškrtnut.

Range

Tento typ formulářového prvku můžete použít k filtrování seznamu položek na základě číselných hodnot. Zde nastavíme vstup tohoto typu, který bude zobrazovat dynamické ceny v rozmezí 0 - 50 USD.

Bude to rychlé, protože všichni používají stejný přístup. Začněte přidáním další vlastnosti ve stavu. Nazývá se price.

const [state, setState] = useState({
  ...
  price: 0,
});

Potom přidejte toto vstupní pole těsně před závěrečnou značku </ form >:

return (
  ...
    <form>
      ...
      <br /><br />
      <label>
        Price (between 0 and 50):
        <input
          type="range"
          name="price"
          min="0"
          max="50"
          value={state.price}
          onChange={handleChange}
        />
      </label>
    </form>
    ...
    <h5>Price : ${state.price}</h5>
  </div>
);

Uložte soubor a otestujte svůj vstup.

Shrnutí

Prvním krokem pro zpracování vstupů formuláře v React je vytvoření kontrolovaného vstupu. Můžete to udělat tak, že necháte stav komponenty spravovat vstup. Poté přiřadíte stav k value nebo checked v závislosti na typu input. Odtamtud máte obslužnou rutinu onChange, která poslouchá změny ve vstupu a řídí jeho stav.

A konečně, pokud máte více než jedno vstupní pole, měli byste přiřadit k vlastnosti name vstupu odpovídající název stavu. To vám umožní spravovat vaše pole pomocí jedné funkce obslužné rutiny.