React 19: useActionState и useFormStatus для форм без боли
-

React 19 упрощает работу с формами через useActionState и useFormStatus. Эти хуки берут на себя стейт загрузки, ошибки и pending-состояния. Забудьте про кастомные useState для каждого сабмита - теперь всё автоматом.
Проблема знакомая: форма отправляется, кнопка не блочится, юзер спамит сабмиты, ошибки не показываются. useActionState решает это одним махом, а useFormStatus даёт точный статус внутри формы. Получается чистый код без лишнего бойлерплейта.
useFormStatus: статус формы без телепатии
useFormStatus - хук из react-dom, который читает состояние родительской
. Он возвращает pending (идёт ли отправка), data (FormData с полями) и другие детали. Главное ограничение: вызывать только внутри компонента, вложенного в form с action. Никаких onSubmit - только action={…}.Представь форму логина. Кнопка должна дизейблиться на время запроса, а под ней показываться “Логин: username…”. Без этого хука пришлось бы пробрасывать стейт через контекст или props drilling. Теперь просто кидаешь useFormStatus в кнопку или спиннер - и всё работает из коробки. Логично подводит к реальным примерам.
Вот базовый usage:
- pending: true пока action выполняется. Идеально для disabled на кнопке.
- data: FormData с name/value полей. Можно get(‘username’) и показать в UI.
- Нюанс: работает только для ближайшей , игнорит вложенные или параллельные.
import { useFormStatus } from 'react-dom'; function SubmitButton() { const { pending, data } = useFormStatus(); return ( <button disabled={pending}> {pending ? 'Отправляем...' : 'Сабмит'} {pending && data?.get('username') && 'Логин: ' + data.get('username')} </button> ); }Поле Тип Описание pending boolean true во время action data FormData/null Данные формы или null method string/null GET/POST из form action function/null Функция из action пропа useActionState: стейт + action в одном флаконе
useActionState из ‘react’ - это тройка: [state, action, isPending]. Передаёшь функцию-обработчик, initialState - и хук сам обновляет стейт после сабмита. Функция получает prevState и FormData, возвращает новый стейт. Автоматически управляет pending.
Кастомный пример: форма добавления юзера. Отправляем на сервер, ловим ошибку или список. Без хука - useState для errors, отдельный для loading, синхронизация вручную. Здесь action цепляется к form action={action}, стейт рендерит ошибки/результат. Киллер-фича - optimistic updates в связке с useOptimistic.
Ключевые фичи:
- state: текущее состояние после action (error, data, success).
- action: готовую функцию для .
- isPending: true во время выполнения (новое в React 19).
- Важно: функция async, возвращает новое состояние для ререндера.
const updateName = async (prevState, formData) => { const name = formData.get('name'); try { // API call return { name, error: null }; } catch { return { ...prevState, error: 'Ошибка сервера' }; } }; const [state, formAction, isPending] = useActionState(updateName, { name: '', error: null }); <form action={formAction}> <input name="name" /> <button disabled={isPending}>Обновить</button> {state.error && <p>{state.error}</p>} </form>Комбо useActionState + useFormStatus: формы без костылей
Вместе эти хуки - мечта фронтендера. useActionState держит глобальный стейт формы (ошибки, данные), useFormStatus - локальный статус для кнопок/спиннеров внутри. Разделение идеальное: state для результата, status для UX во время pending.
Реальный кейс - upload файла. useActionState обрабатывает серверный ответ {success, message}, useFormStatus блочит кнопку и показывает прогресс с data.get(‘file’).name. Нет нужды в Redux или Context - чистый React. Подводит к сравнению подходов.
Преимущества связки:
- Автоматическая блокировка кнопок без props.
- Ошибки из сервера сразу в стейт без try/catch везде.
- FormData нативно: никаких controlled inputs с value/onChange.
- Ограничение: только Server Actions или функции с fetch.
Старый подход Новый с хуками useState(loading), useState(error), useState(data) Один useActionState onSubmit с e.preventDefault() form action={…} Props drilling для кнопок useFormStatus внутри Ручная синхронизация Авто-рендер после action function UploadForm() { const [state, uploadAction, isUploading] = useActionState(handleUpload, null); return ( <form action={uploadAction}> <input name="file" type="file" /> <SubmitButtonWithStatus /> {/* useFormStatus внутри */} {state?.message && <p>{state.message}</p>} </form> ); }Когда хуки показывают зубы: edge cases
Не всё так радужно - есть нюансы. useFormStatus не видит вложенные формы, useActionState требует action функции. Плюс SSR: pending работает только после hydration. Но плюсы перевешивают.
Тестировал на login/uprofile формах - спам сабмитов ушёл, ошибки отображаются миганием стейта. Для сложных форм с валидацией комбинируй с react-hook-form, но базовые кейсы покрыты.
Частые подвохи:
- Вызов useFormStatus вне - всегда null.
- Async функции в action: без await стейт не обновится.
- Инициализация: передавай fallback для SSR.
Формы эволюционируют дальше
useActionState с useFormStatus - шаг к declarative формам в React 19. Осталось за кадром useOptimistic для интерактивности и полная замена react-hook-form в простых кейсах. Стоит поэкспериментировать с Server Actions в Next.js - там раскрываются на полную.
Эти хуки меняют workflow: меньше стейта, больше action. Дальше ждём улучшений в hydration и typed FormData.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.