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.
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.js
tak, 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.
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.
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
a 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.