Урок 04

Отправка формы

onSubmit

Форма обрабатывается через onSubmit. Это позволяет нажать Enter в любом поле и вызвать отправку.

function LoginForm() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');

    function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        console.log({ 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>
    );
}

e.preventDefault() обязателен — иначе браузер перезагрузит страницу.

Кнопка submit

<button type="submit">Отправить</button>

Если type не указан — в форме кнопка по умолчанию submit.

Отправка на сервер

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();

    const res = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
    });

    if (res.ok) {
        // успех
    } else {
        // ошибка
    }
}

Состояние отправки

const [isSubmitting, setIsSubmitting] = useState(false);

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setIsSubmitting(true);

    try {
        await fetch('/api/login', { ... });
    } finally {
        setIsSubmitting(false);
    }
}

<button type="submit" disabled={isSubmitting}>
    {isSubmitting ? 'Отправка...' : 'Войти'}
</button>

Обработка ошибок

const [error, setError] = useState('');

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setError('');

    const res = await fetch('/api/login', { ... });

    if (!res.ok) {
        const data = await res.json();
        setError(data.message ?? 'Ошибка');
        return;
    }

    // успех
}

{error && <p className="error">{error}</p>}

Сброс после отправки

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    await fetch('/api/posts', { ... });
    setTitle('');
    setBody('');
}

Или через form.reset():

const formRef = useRef<HTMLFormElement>(null);

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    await fetch('/api/posts', { ... });
    formRef.current?.reset();
}

Несколько кнопок

Если в форме несколько кнопок — укажи type:

<form onSubmit={handleSubmit}>
    <input value={title} onChange={(e) => setTitle(e.target.value)} />

    <button type="submit">Сохранить</button>
    <button type="button" onClick={handleCancel}>Отмена</button>
    <button type="reset">Очистить</button>
</form>
  • submit — отправляет форму
  • button — обычная кнопка, не отправляет
  • reset — сбрасывает значения

Валидация перед отправкой

function handleSubmit(e: React.FormEvent) {
    e.preventDefault();

    if (!email.includes('@')) {
        setError('Некорректный email');
        return;
    }

    if (password.length < 8) {
        setError('Пароль слишком короткий');
        return;
    }

    // отправка
}

Отправка FormData

Если используешь FormData:

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();

    const formData = new FormData(e.currentTarget as HTMLFormElement);

    await fetch('/api/upload', {
        method: 'POST',
        body: formData,
    });
}

fetch сам установит Content-Type: multipart/form-data.

Двойная отправка

Защита от двойного клика:

<button type="submit" disabled={isSubmitting}>Отправить</button>

Или проверка в обработчике:

async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (isSubmitting) return;

    setIsSubmitting(true);
    // ...
}

Итоги

  • onSubmit + preventDefault
  • Кнопка type="submit"
  • Состояние isSubmitting для индикатора
  • Обработка ошибок
  • form.reset() для сброса
  • type="button" для обычных кнопок внутри формы