Jak otypować zdarzenie onSubmit w formularzach korzystających z Reacta
Data: 2021-11-20 | Autor: Admin | Kategoria: TypeScript
Mając zwykły formularz i próbując otypować onSubmit
, możemy przez chwilę czuć się zakłopotani. Coś nad czym nawet nie trzeba myśleć w JavaScriptcie, w przypadku TypeScripta wymaga albo spotkania się z tym wcześniej, analizy tego co mamy w typach dostarczonych przez Reacta albo poszukanie czegoś w internetach.
Poniżej przykład prostego formularza bez typów, z jednym listenerem nasłuchującym na zdarzenie onSubmit, bez całej otoczki związanej z innymi handlerami i stanem. Pozwoli nam się to skupić na jednej rzeczy.
const handleSubmit = (event) => {
event.preventDefault()
// tutaj mamy dostęp do wartości z formularza,
// które ewentualnie możemy przesłąć dalej lub zrobić z nimi coś innego
console.log(event.currentTarget.elements)
}
const Login = () => {
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Nazwa użytkownika:</label>
<input id="name" type="text" name="name"/>
</div>
<div>
<label htmlFor="password">Hasło:</label>
<input id="password" type="password" name="password"/>
</div>
<div>
<label htmlFor="rememberMe">Zapamiętaj mnie</label>
<input type="checkbox" id="rememberMe" name="rememberMe" />
</div>
<button type="submit">Zaloguj</button>
</form>
)
}
onSubmit typowanie handlera
Żeby mieć dostęp do elementów, które umieściliśmy w formularzu trzeba je otypować. Mamy dwie możliwości albo opisać event albo zdefiniować typ dla handlera. My skorzystamy z tej drugiej opcji.
// przykład otypowania eventu
const handleSubmit = (event: React.FormEvent<LoginFormElement>) => {}
// przykład otypowania handlera
const handleSubmit: React.FormEventHandler<LoginFormElement> = (event) => {}
Poprzez zastosowanie jednego z powyższych rozwiązań definiujemy typ elementu dla event.currentTarget
, którym jest formularz czyli HTMLFormElement
. Ma on dostęp do właściwości elements
, jej typ to interface HTMLFormControlsCollection
. Musimy go rozszerzyć o pola, które dodaliśmy do naszego formalarza. Oczywiście można by to było zrobić za pomocą asercji bezpośrednio w handlerze, bez tego co sugeruję w tym poście ale używanie tego w każdym formularzu może być kłopotliwe i nie wygląda zbyt dobrze. Po opisaniu typów pól możemy bez problemy zacząć używać elements z podpowiedziami.
Cały formularz razem z typami:
import React from 'react';
// ----
// TYPY
// ----
interface FormElements extends HTMLFormControlsCollection {
name: HTMLInputElement;
password: HTMLInputElement;
rememberMe: HTMLInputElement;
}
interface LoginFormElement extends HTMLFormElement {
readonly elements: FormElements
}
type THandleSubmit = React.FormEventHandler<LoginFormElement>;
// -------
// HANDLER
// -------
const handleSubmit: THandleSubmit = (event) => {
event.preventDefault()
console.log(event.currentTarget.elements.name.value)
console.log(event.currentTarget.elements.password.value)
console.log(event.currentTarget.elements.rememberMe.checked)
}
// ---------
// FORMULARZ
// ---------
const Login = () => {
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Nazwa użytkownika:</label>
<input id="name" type="text" name="name"/>
</div>
<div>
<label htmlFor="password">Hasło:</label>
<input id="password" type="password" name="password"/>
</div>
<div>
<label htmlFor="rememberMe">Zapamiętaj mnie</label>
<input type="checkbox" id="rememberMe" name="rememberMe" />
</div>
<button type="submit">Zaloguj</button>
</form>
)
}
export default Login;