TGViewer
Настя Котова // Frontend & Node.js Настя Котова // Frontend & Node.js @startpoint_dev · 1.41K subscribers
Post #56 241
📢 Новые хуки в React 19! Часть 2

В предыдущей части мы посмотрели на хуки useActionState и useFormStatus, а сегодня разберем useOptimistic💡

Напоминаю, что все примеры лежат в нашем репозитории здесь 👉 GitHub

🔍 useOptimistic

Часто в современных интерфейсах используют подход, который называется Optimistic UI. Он заключается в том, что мы предполагаем, что на бэкенде запрос выполнится успешно, поэтому сразу можем показать пользователям обновленное состояние.

Ранее для реализации такого поведения приходилось сильно хитрить. Нельзя просто вызвать useState в обработчике перед асинхронной операцией и ожидать, что React сразу же отрисует новое состояние. Посмотрите на пример 5:


const [optimisticResult, setOptimisticResult] = useState(store);

... = useActionState(async (__: string | null, formData: FormData) => {
setOptimisticResult((prevState) => ({
title: formData.get('title')?.toString() || prevState.title,
description: formData.get('description')?.toString() || prevState.description,
}));

await saveData(formData);

return 'ok';
}, null);


Дело в том, что в React есть специальный механизм оптимизации — Batching, который не позволяет изменениям произойти до получения ответа от сервера.

Эту проблему решает новый хук useOptimistic. Если заменить в примере useState на этот хук, всё заработает правильно. Пример 6 использования нового хука:


const [optimisticResult, setOptimisticResult] = useOptimistic(store);

... = useActionState(async (__: string | null, formData: FormData) => {
setOptimisticResult((prevState) => ({
title: formData.get('title')?.toString() || prevState.title,
description: formData.get('description')?.toString() || prevState.description,
}));

await saveData(formData);

return 'ok';
}, null);


А если наша отправка формы завершится ошибкой, “оптимистичное” состояние автоматически сбросится. Пример использования с обработкой ошибок:


const [optimisticResult, setOptimisticResult] = useOptimistic(store);

... = useActionState(async (__: string | null, formData: FormData) => {
setOptimisticResult((prevState) => ({
title: formData.get('title')?.toString() || prevState.title,
description: formData.get('description')?.toString() || prevState.description,
}));

try {
await saveData(formData);
} catch (e) {
return 'not ok';
}

return 'ok';
}, null);


Дело в том, что при использовании useOptimistic мы передаем в него то значение, для которого хотим сделать оптимистичную версию (в данном примере это store).


const [optimisticResult, setOptimisticResult] = useOptimistic(store);


После выполнения обработчика в хук запишется значение, соответствующее текущему состоянию store.


✍️ Пишите в комментариях, полезней ли на ваш взгляд хук useOptimistic, чем два предыдущих. Мне кажется, этот хук будет использоваться чаще, чем useActionState и useFormStatus.
GitHub GitHub - startpointforl/example-react19-next15: Пример новых хуков в React 19 (+Next 15) Пример новых хуков в React 19 (+Next 15). Contribute to startpointforl/example-react19-next15 development by creating an account on GitHub.
  • 👍 2
More from @startpoint_dev
  1. Sep 21, 2026Я к вам с новым анонсом. Этот год я заканчиваю выступлением на HolyJS! Конференция пройдёт…
  2. Sep 14, 2026В прошлый раз разбирали, зачем нужны using и await using и где они работают. Теперь посмот…
  3. Sep 7, 2026В JavaScript регулярно появляются новые возможности, и не про все из них мы вообще узнаём.…
  4. Aug 31, 2026В цикле про рендеринг мы разбирали конвейер: стили, лейаут, отрисовка, композитинг. Всё эт…
  5. Aug 24, 2026Весной мы обсуждали работу с сырыми данными: ArrayBuffer, Buffer в Node.js, SharedArrayBuf…
  6. Aug 17, 2026Когда я готовила материал для цикла про Next.js, то неожиданно для себя узнала, что в нём…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →