Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке useOptimistic». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`useOptimistic()` - це React-хук, який дозволяє **тимчасово показувати оновлений стан** в UI, поки виконується асинхронна дія (наприклад, відправлення форми, додавання коментаря, видалення елемента тощо). **Ключове:** він робить інтерфейс відповідним і "живим", навіть якщо запит до сервера займе 1-2 секунди, а React сам відкочує стан, якщо операція завершилась помилкою.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке `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 сам керує відкатом і узгодженням даних.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.