Menu

Formularze w React: pola, checkboxy, select i walidacja

Buduj formularze w React z kontrolowanymi polami: pola tekstowe, textarea, select, pola wyboru i przyciski radio, jeden obiekt stanu dla wielu pól, wysyłanie przez onSubmit, pokazywanie błędów walidacji i akcje formularzy z React 19.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Formularz w React trzyma wartość każdego pola w stanie: pole pokazuje value={state} i aktualizuje ją przez onChange. Gdy użytkownik wysyła formularz, handler onSubmit wywołuje e.preventDefault(), żeby zatrzymać przeładowanie strony, a potem używa wartości, które już są w stanie.

Wpisz imię i naciśnij Enter albo kliknij przycisk. Potem usuń linię e.preventDefault();: podgląd pokaże pola, które przeglądarka wysłałaby przy natywnym wysłaniu, które na prawdziwej stronie dodatkowo by ją przeładowało.

Pole, którego wartość pochodzi ze stanu, nazywa się polem kontrolowanym. Alternatywę, czyli pozwolenie DOM na przechowywanie wartości i odczytanie jej później, omawia strona o komponentach kontrolowanych i niekontrolowanych.

Pola tekstowe i textarea

Każde pole tekstowe działa tak samo: value ze stanu, onChange odczytuje e.target.value. <textarea> stosuje ten sam wzorzec. W HTML jej tekst trafia między tagi, ale w React przekazujesz go jako value.

Ponieważ sam ustawiasz wartość, możesz zmienić to, co wpisał użytkownik, zanim się pokaże: pole tytułu zamienia każdą literę na wielką. Licznik znaków aktualizuje się przy każdym naciśnięciu klawisza, bo body jest stanem, a każda zmiana renderuje ponownie.

Select

<select> przyjmuje value na samym elemencie select, a nie selected na opcji. e.target.value to value wybranej opcji.

Przy wielokrotnym wyborze dodaj multiple i przekaż tablicę jako value. Wybrane opcje odczytasz przez Array.from(e.target.selectedOptions, (o) => o.value).

Pola wyboru i przyciski radio

Pole wyboru kontroluje się przez checked, a nie value, a jego handler odczytuje e.target.checked, czyli true albo false. Przyciski radio w grupie mają wspólne name; każdy jest zaznaczony, gdy stan równa się jego wartości.

Odczyt e.target.value na polu wyboru to częsty błąd: dla pola bez atrybutu value zwraca tekst "on" niezależnie od tego, czy pole jest zaznaczone.

Jeden obiekt stanu dla wielu pól

Formularz z dziesięcioma polami nie potrzebuje dziesięciu wywołań useState i dziesięciu handlerów. Trzymaj jeden obiekt, nadaj każdemu polu name odpowiadające kluczowi i napisz jeden handler, który używa nazwy jako wyliczanego klucza: [e.target.name].

Handler sprawdza typ pola, żeby pole wyboru zapisywało wartość logiczną, a pozostałe tekst. Nowe pole dodajesz, dodając klucz do obiektu początkowego i pole z tym samym name; handler nie wymaga zmian. Spread zachowuje każde inne pole (zobacz aktualizowanie tablic i obiektów).

Wysyłanie formularza

Logikę wysyłania umieść w onSubmit formularza, a nie w onClick przycisku. onSubmit uruchamia się też, gdy użytkownik naciśnie Enter w polu tekstowym, czego handler kliknięcia by nie wychwycił. <button> wewnątrz formularza jest domyślnie przyciskiem wysyłania; innym przyciskom nadaj type="button", żeby nie wysyłały formularza.

Otwórz konsolę, wpisz hasło i naciśnij Enter: formularz wypisze cały obiekt. Kliknięcie "Clear" niczego nie wypisuje, bo ma type="button". Usuń ten atrybut, a Clear też zacznie wysyłać formularz.

Walidacja i pokazywanie błędów

Prosta walidacja to funkcja, która przyjmuje wartości i zwraca obiekt z komunikatami. Uruchom ją przy wysyłaniu, zapisz wynik w stanie i pokaż każdy komunikat pod jego polem. Wyłącz przycisk wysyłania na czas trwania żądania, żeby podwójne kliknięcie nie wysłało formularza dwa razy.

Kliknij Save przy pustych polach, żeby zobaczyć oba komunikaty, a potem je wypełnij. saveProfile zastępuje prawdziwe żądanie: czeka 800 milisekund i się rozwiązuje. Atrybut noValidate wyłącza własne dymki walidacji przeglądarki, żeby pokazywały się tylko twoje komunikaty; usuń go i dodaj required do pola, żeby porównać.

Błędy można też wyliczać podczas renderowania zamiast je przechowywać, na przykład const emailError = form.email && !form.email.includes('@'), co pokazuje komunikat w trakcie pisania. Wybierz moment, który pasuje do formularza: przy wysyłaniu jest spokojniej, a w trakcie pisania informacja zwrotna przychodzi szybciej.

Akcje formularzy w React 19

React 19 dodaje kolejny sposób obsługi formularza. Przekaż funkcję do propsa action formularza. React sam zablokuje przeładowanie strony i wywoła funkcję z obiektem FormData, który zawiera każde pole mające name. Pola w ogóle nie potrzebują stanu: są niekontrolowane, a React czyści je po zakończeniu akcji.

Wpisz własny komentarz i opublikuj go. Lista pokazuje twój tekst, a pole wraca do Nice docs: po rozwiązaniu akcji React resetuje niekontrolowane pola do ich defaultValue. Akcja może być asynchroniczna, a w trakcie jej działania React traktuje aktualizację jako przejście (transition).

Żeby pokazać stan oczekiwania albo błąd z akcji, owiń ją w useActionState, który zwraca najnowszy wynik, opakowaną akcję dla formularza i flagę isPending. Przycisk głęboko w formularzu może też odczytać stan oczekiwania przez useFormStatus z react-dom:

import { useFormStatus } from 'react-dom';

function SubmitButton() {
    const { pending } = useFormStatus();
    return <button disabled={pending}>{pending ? 'Posting...' : 'Post'}</button>;
}

useFormStatus nie jest załadowany w tutejszych edytorach, więc pojawia się tylko w tym statycznym bloku. Trzeba go wywołać z komponentu wyrenderowanego wewnątrz <form>, a nie w komponencie, który renderuje formularz.

W React 19 działają oba podejścia: kontrolowany stan z onSubmit i akcje formularzy z FormData. Pola kontrolowane pasują do formularzy, które reagują w trakcie pisania (walidacja na żywo, licznik znaków, pola zależne od siebie). Akcje pasują do formularzy, w których wartości potrzebujesz dopiero przy wysłaniu.

Najczęściej zadawane pytania

Jak w React pobrać wartość pola input?

Przechowuj ją w stanie i aktualizuj z onChange: <input value={name} onChange={e => setName(e.target.value)} />. Bieżący tekst jest wtedy zawsze w name. Dla pól wyboru odczytuj e.target.checked zamiast e.target.value.

Jak w React zablokować przeładowanie strony przez formularz?

Wywołaj e.preventDefault() na początku handlera onSubmit. Bez tego przeglądarka wykonuje zwykłe wysłanie formularza, które przechodzi na inną stronę i przeładowuje ją.

Jak w React obsłużyć wiele pól jednym stanem?

Trzymaj w stanie jeden obiekt, nadaj każdemu polu name odpowiadające kluczowi i użyj jednego handlera z wyliczanym kluczem: setForm({ ...form, [e.target.name]: e.target.value }).

Dlaczego textarea w React używa value zamiast children?

W HTML tekst textarea znajduje się między jej tagami, ale w React przekazujesz go jako value (albo defaultValue), tak samo jak w polu input. Dzięki temu każde pole tekstowe w formularzu Reacta działa tak samo.

Co to są akcje formularzy w React 19?

W React 19 możesz przekazać funkcję do <form action={fn}>. React blokuje przeładowanie strony, wywołuje funkcję z FormData formularza i po zakończeniu resetuje niekontrolowane pola. useActionState dodaje do tego flagę oczekiwania i wynik.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ