React 19: useOptimistic и useActionState для пессимистичных форм с progressive enhancement
-

React 19 притащил useOptimistic и useActionState - хуки, которые меняют правила игры с формами. Они позволяют делать пессимистичные обновления: UI показывает реальное состояние с фолбэками, пока сервер думает. Это решает боль задержек и спиннеров - юзер сразу видит, что происходит, даже если сетка легла.
Progressive enhancement здесь в теме: формы работают без JS, а с React’ом добавляется магия optimistic’а. Зачем это? Меньше бойлерплейта, чище стейт, надежнее UX. Погнали разбирать на примерах.
useActionState: стейт действий без лишнего кода
useActionState берет на себя управление стейтом асинхронных экшенов - pending, success, error в одном хуке. Вместо кучи useState для loading/error/success пишешь одну строку. Форма подключается через action={formAction}, и React сам обновляет UI по результату.
Представь форму логина: юзер жмет submit, сервер проверяет креды. Без этого хука пришлось бы вручную сетить isLoading=true, потом обрабатывать ответ. С useActionState стейт всегда актуальный, кнопка дизаблится на pending. Это упрощает код в 2-3 раза, особенно с серверными экшенами.
Ключевые фичи:
- Возвращает [state, action] - state это объект с pending/error/lastSuccess.
- Поддерживает progressive enhancement: без JS форма шлет POST на сервер.
- Интегрируется с useOptimistic для гибридных обновлений.
Свойство Описание Пример pending true во время запроса disabled={pending} error Строка с ошибкой сервера {error && {error}
}lastSuccess Результат успеха {lastSuccess?.message} Пример простейшей формы:
const [state, formAction] = useActionState(loginAction, {error: null}); <form action={formAction}> <input name="email" /> <button disabled={state.pending}>Login</button> {state.error && <p style={{color: 'red'}}>{state.error}</p>} </form>Нюанс: initialState задай null или {}, чтобы избежать фликера.
useOptimistic для пессимистичных обновлений
useOptimistic рендерит UI сразу по ожидаемому результату, откатывает при ошибке. Для пессимистичных форм это идеал: показывай фолбэк (спиннер, “отправляем…”), пока сервер не ответил. Комбинируй с useActionState - optimisticState берет реальный стейт и мутирует его.
Возьми список тасок: юзер добавляет новую, UI сразу показывает “sending…”. Сервер ответил - обновляем, ошибка - роллбэк. Без этого хука приходилось дублировать стейт optimistic/real. Теперь один хук - два стейта: реальный и UI-версия.
Как это работает:
const [optimisticTasks, addOptimistic] = useOptimistic(tasks, (state, newTask) => [...state, {text: newTask, sending: true}]);- В formAction: addOptimistic(formData.get(‘task’)); await sendToServer();
- При ошибке стейт откатывается автоматически.
Плюсы пессимистичного подхода:
- Fallback’и: всегда показывай pending-state, даже оффлайн.
- Progressive: форма работает без React.
- Rollback: ошибка? optimisticState синхронится с реальным.
Optimistic vs Pessimistic Когда юзать Optimistic Лайки, комментарии (предполагаем успех) Pessimistic Формы с критичными данными (логин, оплата) Код для тасок:
function Tasks({tasks, sendTasks}) { const [optimisticTasks, addOptimisticTask] = useOptimistic(tasks, (state, newTask) => [...state, {text: newTask, sending: true}]); async function formAction(formData) { addOptimisticTask(formData.get('task')); await sendTasks(formData); } return ( <> {optimisticTasks.map(t => <div>{t.text} {t.sending && '(отправляем...)'}</div>)} <form action={formAction}><input name="task" /><button>Add</button></form> </> ); }Комбо: useActionState + useOptimistic с progressive enhancement
Соединяем хуки: useActionState управляет form-state, useOptimistic - UI-обновлениями. Форма шлет серверный экшен, optimistic добавляет фолбэк сразу. Progressive enhancement на месте: без JS - обычный POST, с JS - мгновенный фидбек.
Пример - редактирование профиля. Юзер меняет email, форма показывает “saving…” optimistic’но, сервер валидирует. Ошибка? Роллбэк + error из useActionState. Это убивает спиннеры и лоадеры - UI живой всегда.
Шаги реализации:
- Создай серверный action с async/await.
- Подключи useActionState для стейта формы.
- Добавь useOptimistic для списка/формы.
- В action: optimistic update -> await server -> sync.
const [state, formAction] = useActionState(updateProfile, {error: null}); const [optimisticProfile, updateOptimistic] = useOptimistic(profile, (st, newEmail) => ({...st, email: newEmail, saving: true})); // В action: updateOptimistic(formData.get('email')); return await api.update();Сравнение подходов:
Подход Boilerplate UX Progressive useState + useEffect Высокий Спиннеры Нет useActionState solo Низкий Хороший Да + useOptimistic Минимальный
ИдеалДа Важно: uncontrolled inputs - не синхронизируй value с state, пусть FormData рулит.
Пессимистичные фолбэки - когда оптимизм подведет
Фолбэки в пессимистичном стиле - это pending-states в optimisticState. Показывай “loading”, “error”, не жди сервера. С useFormStatus внутри формы - кнопка сама знает pending. Комбо с роутерами типа Next.js - серверные actions на стероидах.
Думай о слабом интернете: optimistic рендерит фолбэк, useActionState ловит error. Нет нужды в глобальном loading - локальные хуки все тянут.
Фичи для продакшена:
- Rollback в catch: addOptimistic((prev) => prev - 1) для лайков.
- Hydration: SSR + client optimistic синхронятся.
- Error boundaries не нужны - стейт сам хэндлит.
Код фолбэка:
function LikeButton({likes}) { const [optLikes, addOpt] = useOptimistic(likes, (prev) => prev + 1); async function handle() { addOpt(); try { await fetch('/like'); } catch { addOpt((p) => p - 1); } } return <button onClick={handle}>❤️ {optLikes}</button>; }Гибридные паттерны выходят за рамки форм
useOptimistic + useActionState работают не только с формами - лайки, чат, CRUD. Остается копать интеграцию с TanStack Query или SWR для кэша. Подумай о custom hooks для типичных сценариев: optimisticDelete, optimisticPatch. В React 19 это база для быстрых apps - меньше костылей, больше нативности.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.