React 19: useFormStatus для динамической индикации загрузки форм без лишнего состояния
-

В React 19 появился хук useFormStatus, который упрощает работу с формами. Он позволяет отслеживать состояние отправки прямо в дочерних компонентах, без создания дополнительного состояния в родителе. Это решает проблему дублирования loading-логики и делает код чище.
Зачем это нужно? Раньше для индикации загрузки приходилось вручную управлять состоянием через useState или Context. Теперь useFormStatus дает доступ к pending, data, method и action автоматически. Проблемы с асинхронной отправкой форм уходят на второй план - кнопки отключаются сами, спиннеры показываются без лишнего кода.
Что возвращает useFormStatus и как это работает
Хук useFormStatus вызывается только внутри компонента, вложенного в тег
<form>. Он возвращает объект с четырьмя свойствами: pending (булево, показывает, идет ли отправка), data (FormData с данными формы), method (‘get’ или ‘post’) и action (URL или функция для отправки). Это позволяет дочерним компонентам реагировать на состояние формы без пропсов или глобального стора.Представьте форму логина: поле email, пароль и кнопка. Во время отправки нужно отключить кнопку и показать ‘Submitting…’. Без useFormStatus пришлось бы поднимать состояние вверх. С ним кнопка сама узнает о pending и обновится. Хук работает только с родительской формой - если компонент не внутри
<form>, pending всегда false.Вот ключевые свойства в действии:
- pending: true/false - основное для спиннеров и отключения элементов. Активируется при submit и деактивируется после завершения действия.
- data - FormData с полями формы. Полезно для превью: ‘Отправляем username: john_doe’.
- method - HTTP-метод формы, по умолчанию ‘get’.
- action - цель отправки, функция или URL.
Свойство Тип Когда использовать pending boolean Спиннеры, disabled на кнопках data FormData/null Превью данных перед отправкой method string Логика в зависимости от GET/POST action string/function Динамическая маршрутизация Простой пример с кнопкой и загрузкой
Создадим форму регистрации. Родительский компонент содержит
<form action={someAction}>, а внутри - отдельный компонент для кнопки. useFormStatus в кнопке читает pending и меняет текст/состояние автоматически. Никаких пропсов не нужно передавать.Код выглядит так: импорт из ‘react-dom’, вызов хука в SubmitButton, использование pending для disabled и текста. Во время симуляции API-запроса (setTimeout) кнопка показывает ‘Signing up…’ и блокируется. После успеха или ошибки состояние сбрасывается само. Это избавляет от useState в родителе для loading.
- Создайте action-функцию с задержкой:
async function signupAction(formData) { await new Promise(r => setTimeout(r, 1000)); return {success: true}; }. - В форме:
<form action={formAction}><input name="email"/><SubmitButton/></form>.
Важно: хук работает только с server actions или form actions в React 19.
function SubmitButton() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending}> {pending ? "Отправляем..." : "Зарегистрироваться"} </button> ); }Сравнение с традиционным подходом в React 18
В старых версиях формы обрабатывались через onSubmit с useState. Нужно было: setLoading(true) в handleSubmit, fetch, затем setLoading(false). Это создавало boilerplate: состояние, эффекты, обработка ошибок. Плюс Context для дочерних компонентов.
С useFormStatus + useActionState код сокращается вдвое. Нет ручного управления pending - хук синхронизируется с формой. Для сложных форм (логин + профиль) это спасение: каждый ребенок знает статус без пропсов. Минус - только для DOM-форм, не для кастомных.
Подход useState (React 18) useFormStatus (React 19) Состояние Ручное useState Автоматическое из хука Дочерние компоненты Context/props Прямой доступ в любом ребенке Код 20+ строк 5-10 строк Ошибки setError вручную Через useActionState - Традиционный:
const [loading, setLoading] = useState(false);+ обработчики. - Новый:
const { pending } = useFormStatus();- и все.
Расширенные сценарии: превью данных и ошибки
useFormStatus не только для pending. Свойство data позволяет показывать ‘Запрос username: user123’ прямо на кнопке или рядом. Полезно для подтверждения перед отправкой. Комбинируйте с useOptimistic для мгновенного UI-обновления.
В форме имени пользователя: input + кнопка с превью data?.get(‘username’). Во время отправки input disabled={pending}. После - показ результата из action. Это создает отзывчивый интерфейс без лишнего состояния. Для ошибок используйте useActionState параллельно.
- Превью на кнопке:
{data && <span>Отправка: ${data.get('name')}</span>}. - Блокировка полей:
disabled={pending}на input. - Комбо с useActionState:
[state, formAction] = useActionState(actionFn, initialState).
function UsernamePreview() { const { pending, data } = useFormStatus(); return ( <p>{pending && data ? `Запрашиваем ${data.get('username')}...` : ''}</p> ); }Когда хук не сработает и как фиксить
useFormStatus возвращает pending: false всегда, если компонент не внутри
<form>. Проверьте в DevTools: хук ищет ближайшую родительскую форму. Решение - обернуть в form или переместить компонент внутрь.Еще проблема: кастомные кнопки без type=“submit”. Укажите тип явно. Для SSR pending может отставать - используйте Suspense. Тестируйте в production-билде, симулируя медленный fetch.
- Не вложен в form: Переместите компонент внутрь.
- Не срабатывает submit: Проверьте action на сервере.
- Несовместимость с библиотеками вроде react-hook-form - пока экспериментально.
Хук в экосистеме React 19 форм
useFormStatus идеально сочетается с useActionState и useOptimistic. Вместе они заменяют весь boilerplate для форм: состояние, loading, оптимистичные обновления. Для больших приложений это норма - меньше багов, чище код. Остается экспериментировать с data для кастомных превью и думать, как интегрировать с TypeScript для типизации FormData.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.