Skip to main content

Що таке useOptimistic

Що таке useOptimistic()

useOptimistic() - це React-хук, який дозволяє тимчасово показувати оновлений стан в UI, поки виконується асинхронна дія (наприклад, відправлення форми, додавання коментаря, видалення елемента тощо).

Іншими словами: він допомагає зробити інтерфейс відповідним і "живим", навіть якщо запит до сервера займе 1-2 секунди.


Сигнатура

javascript
const [optimisticState, addOptimistic] = useOptimistic(baseState, updateFn);
АргументОпис
baseStateПоточний реальний стан (наприклад, список коментарів, масив задач тощо)
updateFnФункція (state, newValue) => newState, що описує, як відобразити "оптимістичний" стан
Повертає[optimisticState, addOptimistic] - поточний стан (з урахуванням оптимізму) і функція для його тимчасової зміни

Приклад з життя

Припустимо, ти робиш чат, де повідомлення відправляються на сервер. Користувач натискає "Надіслати", але відповідь від API приходить через секунду. Без оптимізму UI зависає - повідомлення з'являється лише після відповіді.

З useOptimistic() ти можеш показати нове повідомлення одразу, а потім React автоматично оновить UI, коли сервер відповість.


Приклад: додавання коментаря

javascript
import { useOptimistic, useActionState } from 'react'; async function postComment(prevState, formData) { const comment = formData.get('comment'); await api.addComment(comment); return { success: true }; } export default function Comments({ comments }) { const [state, formAction] = useActionState(postComment, null); const [optimisticComments, addOptimistic] = useOptimistic( comments, (currentComments, newComment) => [ ...currentComments, { id: Math.random(), text: newComment, pending: true }, ] ); async function handleSubmit(formData) { const comment = formData.get('comment'); addOptimistic(comment); // миттєво показати новий коментар await formAction(formData); // дочекатися сервера } return ( <form action={handleSubmit}> <ul> {optimisticComments.map(c => ( <li key={c.id}> {c.text} {c.pending && '(sending...)'} </li> ))} </ul> <input name="comment" /> <button type="submit">Send</button> </form> ); }

Тут:

  • useOptimistic створює "віртуальний" список коментарів з новим повідомленням одразу;
  • Коли сервер відповість, React замінить оптимістичний стан на реальний;
  • Користувач одразу бачить, що його коментар з'явився.

Інші приклади

Видалення елемента

javascript
const [optimisticTodos, removeOptimistic] = useOptimistic( todos, (current, id) => current.filter(t => t.id !== id) ); async function handleDelete(id) { removeOptimistic(id); // миттєво приховати await api.deleteTodo(id); // потім сервер підтвердить }

Лайки

javascript
const [optimisticLikes, toggleOptimistic] = useOptimistic( likes, (current, delta) => current + delta ); async function handleLike() { toggleOptimistic(1); await api.likePost(); }

Як це працює під капотом

  1. Ти зберігаєш "реальний" стан (наприклад, comments чи likes).
  2. React створює поверх нього "оптимістичний" стан, який застосовується миттєво.
  3. Коли Action завершилась (або дані оновилися з сервера), React відкидає оптимістичний стан і синхронізується з реальним.
  4. Якщо операція завершилася помилкою - React автоматично "відкотить" UI до попереднього стану.

Відмінність від ручного підходу (useState)

Без useOptimistic тобі довелося б писати:

javascript
setComments([...comments, newComment]); // вручну try { await api.addComment(newComment); } catch { setComments(oldComments); // відкат }

Проблеми:

  • потрібно зберігати старий стан для відкату,
  • складно синхронізувати з іншими оновленнями,
  • може конфліктувати з concurrent rendering.

З useOptimistic:

  • React сам відстежує "віртуальні" зміни,
  • автоматично синхронізує і відкочує стан,
  • працює безпечно в конкурентному режимі.

Коли використовувати useOptimistic

Підходить для:

  • Інтерфейсів із затримками відповіді (форми, коментарі, лайки, кошики);
  • Списків і таблиць, де додаються/видаляються елементи;
  • UX-оптимізації - користувач бачить дію "одразу".

Не варто використовувати:

  • Для даних, де помилка має блокувати дію (наприклад, платежі);
  • Для стану, що залежить від складних транзакцій на сервері;
  • Коли "оптимістична" версія може збити користувача з пантелику.

Порівняння з іншими хуками React 19

ХукПризначення
useActionState()Керує станом асинхронної дії (результат, помилка, pending)
useFormStatus()Відстежує статус відправлення конкретної форми
useOptimistic()Тимчасово оновлює UI для миттєвого зворотного зв'язку
useTransition()Робить оновлення "низькопріоритетними", але не оптимістичними

Комбо-приклад: useOptimistic + useActionState

javascript
async function addTask(prev, formData) { const task = formData.get('task'); await api.addTask(task); return { success: true }; } export default function TaskList({ tasks }) { const [state, formAction] = useActionState(addTask, null); const [optimisticTasks, addOptimistic] = useOptimistic( tasks, (list, newTask) => [...list, { id: Math.random(), text: newTask, pending: true }] ); async function handleSubmit(formData) { const task = formData.get('task'); addOptimistic(task); await formAction(formData); } return ( <form action={handleSubmit}> <ul> {optimisticTasks.map(t => ( <li key={t.id}>{t.text} {t.pending && '(saving...)'}</li> ))} </ul> <input name="task" /> <button type="submit">Add</button> </form> ); }

Користувач бачить нову задачу миттєво, React оновлює її остаточно, коли сервер підтвердить.


Підсумок

useOptimistic() - це React-хук для створення миттєвого відгуку UI при асинхронних змінах, поки сервер обробляє дію.

Він ідеально підходить для UX, де важливе відчуття "швидкості", при цьому React сам керує відкатом і узгодженням даних.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.