Skip to main content
Практика завдань

Форми та обробка форм у React

Обробка Форм в React

React надає два підходи для обробки форм: контрольовані компоненти (React керує станом форми) та неконтрольовані компоненти (DOM керує станом форми). React 19 також вводить дії форм.


Контрольовані Компоненти

Стан React є єдиним джерелом істини для значень введення:

tsx
function LoginForm() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); login({ email, password }); }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={e => setEmail(e.target.value)} /> <input type="password" value={password} onChange={e => setPassword(e.target.value)} /> <button type="submit">Увійти</button> </form> ); }

Неконтрольовані Компоненти (useRef)

DOM зберігає дані; React читає їх за потреби:

tsx
function SearchForm() { const inputRef = useRef<HTMLInputElement>(null); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); console.log(inputRef.current?.value); // Читання з DOM }; return ( <form onSubmit={handleSubmit}> <input ref={inputRef} type="text" defaultValue="" /> <button type="submit">Пошук</button> </form> ); }

Складна Форма з useReducer

tsx
type FormState = { name: string; email: string; role: string; errors: Record<string, string>; }; type FormAction = | { type: "SET_FIELD"; field: string; value: string } | { type: "SET_ERROR"; field: string; error: string } | { type: "RESET" }; function formReducer(state: FormState, action: FormAction): FormState { switch (action.type) { case "SET_FIELD": return { ...state, [action.field]: action.value }; case "SET_ERROR": return { ...state, errors: { ...state.errors, [action.field]: action.error } }; case "RESET": return { name: "", email: "", role: "", errors: {} }; } } function RegistrationForm() { const [state, dispatch] = useReducer(formReducer, { name: "", email: "", role: "", errors: {} }); return ( <form> <input value={state.name} onChange={e => dispatch({ type: "SET_FIELD", field: "name", value: e.target.value })} /> {state.errors.name && <span>{state.errors.name}</span>} {/* ... більше полів */} </form> ); }

React Hook Form (Популярна Бібліотека)

tsx
import { useForm } from "react-hook-form"; interface FormData { email: string; password: string; age: number; } function SignUpForm() { const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>(); const onSubmit = async (data: FormData) => { await createUser(data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("email", { required: "Email є обов'язковим", pattern: { value: /^[^@]+@[^@]+$/, message: "Неправильний email" } })} /> {errors.email && <span>{errors.email.message}</span>} <input type="password" {...register("password", { required: true, minLength: 8 })} /> {errors.password && <span>Мінімум 8 символів</span>} <input type="number" {...register("age", { min: 18, max: 120 })} /> <button disabled={isSubmitting}> {isSubmitting ? "Відправка..." : "Зареєструватися"} </button> </form> ); }

Контрольовані vs Неконтрольовані

ОсобливістьКонтрольованіНеконтрольовані
Значення зберігається вСтані ReactDOM
ВалідаціяПри кожній змініПри відправці
ПеререндериПри кожному натисканні клавішіМінімальні
ВикористанняСкладні форми, жива валідаціяПростi форми, введення файлів
БібліотекаReact Hook Form, FormikВбудована форма, useRef

Шаблон Валідації Форм

tsx
function validateEmail(email: string): string | null { if (!email) return "Email є обов'язковим"; if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) return "Неправильний email"; return null; } function Form() { const [email, setEmail] = useState(""); const [error, setError] = useState<string | null>(null); const [touched, setTouched] = useState(false); const handleBlur = () => { setTouched(true); setError(validateEmail(email)); }; return ( <div> <input value={email} onChange={e => { setEmail(e.target.value); if (touched) setError(validateEmail(e.target.value)); }} onBlur={handleBlur} /> {touched && error && <span className="error">{error}</span>} </div> ); }

Важливо:

Використовуйте контрольовані компоненти, коли вам потрібна валідація в реальному часі, умовна логіка або синхронізований стан. Використовуйте неконтрольовані компоненти для простих форм або введення файлів. Для виробничих додатків надавайте перевагу React Hook Form — це мінімізує перерендери та забезпечує відмінну валідацію. Завжди також проводьте валідацію на сервері.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань