<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[React 19: useActionState и useFormStatus для форм без боли]]></title><description><![CDATA[<p dir="auto"><img src="/assets/uploads/files/24/a8/ae/1774096882808-generated_1774096866424.webp" alt="Обложка: React 19: useActionState с useFormStatus для упрощения состояний форм с автоматической обработкой ошибок и загрузки" class=" img-fluid img-markdown" /></p>
<p dir="auto">React 19 упрощает работу с формами через useActionState и useFormStatus. Эти хуки берут на себя стейт загрузки, ошибки и pending-состояния. Забудьте про кастомные useState для каждого сабмита - теперь всё автоматом.</p>
<p dir="auto">Проблема знакомая: форма отправляется, кнопка не блочится, юзер спамит сабмиты, ошибки не показываются. useActionState решает это одним махом, а useFormStatus даёт точный статус внутри формы. Получается чистый код без лишнего бойлерплейта.</p>
<h2>useFormStatus: статус формы без телепатии</h2>
<p dir="auto">useFormStatus - хук из react-dom, который читает состояние родительской </p>. Он возвращает pending (идёт ли отправка), data (FormData с полями) и другие детали. Главное ограничение: вызывать только внутри компонента, вложенного в form с action. Никаких onSubmit - только action={…}.<p></p>
<p dir="auto">Представь форму логина. Кнопка должна дизейблиться на время запроса, а под ней показываться “Логин: username…”. Без этого хука пришлось бы пробрасывать стейт через контекст или props drilling. Теперь просто кидаешь useFormStatus в кнопку или спиннер - и всё работает из коробки. Логично подводит к реальным примерам.</p>
<p dir="auto">Вот базовый usage:</p>
<ul>
<li><strong>pending</strong>: true пока action выполняется. Идеально для disabled на кнопке.</li>
<li><strong>data</strong>: FormData с name/value полей. Можно get(‘username’) и показать в UI.</li>
<li><em>Нюанс</em>: работает только для ближайшей , игнорит вложенные или параллельные.</li>
</ul>
<pre><code>import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending, data } = useFormStatus();
  return (
    &lt;button disabled={pending}&gt;
      {pending ? 'Отправляем...' : 'Сабмит'}
      {pending &amp;&amp; data?.get('username') &amp;&amp; 'Логин: ' + data.get('username')}
    &lt;/button&gt;
  );
}
</code></pre>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Поле</th>
<th>Тип</th>
<th>Описание</th>
</tr>
</thead>
<tbody>
<tr>
<td>pending</td>
<td>boolean</td>
<td>true во время action</td>
</tr>
<tr>
<td>data</td>
<td>FormData/null</td>
<td>Данные формы или null</td>
</tr>
<tr>
<td>method</td>
<td>string/null</td>
<td>GET/POST из form</td>
</tr>
<tr>
<td>action</td>
<td>function/null</td>
<td>Функция из action пропа</td>
</tr>
</tbody>
</table>
<h2>useActionState: стейт + action в одном флаконе</h2>
<p dir="auto">useActionState из ‘react’ - это тройка: [state, action, isPending]. Передаёшь функцию-обработчик, initialState - и хук сам обновляет стейт после сабмита. Функция получает prevState и FormData, возвращает новый стейт. Автоматически управляет pending.</p>
<p dir="auto">Кастомный пример: форма добавления юзера. Отправляем на сервер, ловим ошибку или список. Без хука - useState для errors, отдельный для loading, синхронизация вручную. Здесь action цепляется к form action={action}, стейт рендерит ошибки/результат. Киллер-фича - optimistic updates в связке с useOptimistic.</p>
<p dir="auto">Ключевые фичи:</p>
<ul>
<li><strong>state</strong>: текущее состояние после action (error, data, success).</li>
<li><strong>action</strong>: готовую функцию для .</li>
<li><strong>isPending</strong>: true во время выполнения (новое в React 19).</li>
<li><em>Важно</em>: функция async, возвращает новое состояние для ререндера.</li>
</ul>
<pre><code>const updateName = async (prevState, formData) =&gt; {
  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 });

&lt;form action={formAction}&gt;
  &lt;input name="name" /&gt;
  &lt;button disabled={isPending}&gt;Обновить&lt;/button&gt;
  {state.error &amp;&amp; &lt;p&gt;{state.error}&lt;/p&gt;}
&lt;/form&gt;
</code></pre>
<h2>Комбо useActionState + useFormStatus: формы без костылей</h2>
<p dir="auto">Вместе эти хуки - мечта фронтендера. useActionState держит глобальный стейт формы (ошибки, данные), useFormStatus - локальный статус для кнопок/спиннеров внутри. Разделение идеальное: state для результата, status для UX во время pending.</p>
<p dir="auto">Реальный кейс - upload файла. useActionState обрабатывает серверный ответ {success, message}, useFormStatus блочит кнопку и показывает прогресс с data.get(‘file’).name. Нет нужды в Redux или Context - чистый React. Подводит к сравнению подходов.</p>
<p dir="auto">Преимущества связки:</p>
<ul>
<li>Автоматическая блокировка кнопок без props.</li>
<li>Ошибки из сервера сразу в стейт без try/catch везде.</li>
<li><strong>FormData нативно</strong>: никаких controlled inputs с value/onChange.</li>
<li><em>Ограничение</em>: только Server Actions или функции с fetch.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Старый подход</th>
<th>Новый с хуками</th>
</tr>
</thead>
<tbody>
<tr>
<td>useState(loading), useState(error), useState(data)</td>
<td>Один useActionState</td>
</tr>
<tr>
<td>onSubmit с e.preventDefault()</td>
<td>form action={…}</td>
</tr>
<tr>
<td>Props drilling для кнопок</td>
<td>useFormStatus внутри</td>
</tr>
<tr>
<td>Ручная синхронизация</td>
<td>Авто-рендер после action</td>
</tr>
</tbody>
</table>
<pre><code>function UploadForm() {
  const [state, uploadAction, isUploading] = useActionState(handleUpload, null);
  return (
    &lt;form action={uploadAction}&gt;
      &lt;input name="file" type="file" /&gt;
      &lt;SubmitButtonWithStatus /&gt; {/* useFormStatus внутри */}
      {state?.message &amp;&amp; &lt;p&gt;{state.message}&lt;/p&gt;}
    &lt;/form&gt;
  );
}
</code></pre>
<h2>Когда хуки показывают зубы: edge cases</h2>
<p dir="auto">Не всё так радужно - есть нюансы. useFormStatus не видит вложенные формы, useActionState требует action функции. Плюс SSR: pending работает только после hydration. Но плюсы перевешивают.</p>
<p dir="auto">Тестировал на login/uprofile формах - спам сабмитов ушёл, ошибки отображаются миганием стейта. Для сложных форм с валидацией комбинируй с react-hook-form, но базовые кейсы покрыты.</p>
<p dir="auto">Частые подвохи:</p>
<ul>
<li>Вызов useFormStatus вне  - всегда null.</li>
<li><strong>Async функции в action</strong>: без await стейт не обновится.</li>
<li>Инициализация: передавай fallback для SSR.</li>
</ul>
<h2>Формы эволюционируют дальше</h2>
<p dir="auto">useActionState с useFormStatus - шаг к declarative формам в React 19. Осталось за кадром useOptimistic для интерактивности и полная замена react-hook-form в простых кейсах. Стоит поэкспериментировать с Server Actions в Next.js - там раскрываются на полную.</p>
<p dir="auto">Эти хуки меняют workflow: меньше стейта, больше action. Дальше ждём улучшений в hydration и typed FormData.</p>
]]></description><link>https://forum.exlends.ru/topic/1809/react-19-useactionstate-i-useformstatus-dlya-form-bez-boli</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 02:55:59 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1809.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 21 Mar 2026 12:41:23 GMT</pubDate><ttl>60</ttl></channel></rss>