Що таке "optimistic update"?
Що таке "optimistic update"
Optimistic update (оптимістичне оновлення) - це підхід, за якого UI оновлюється відразу, ще до того, як сервер підтвердив зміну даних.
Тобто застосунок оптимістично припускає, що операція на сервері завершиться успішно, і оновлює інтерфейс миттєво, щоб користувач не відчував затримку.
Приклад без оптимістичного оновлення:
async function handleLike(postId) {
await fetch(`/api/posts/${postId}/like`, { method: "POST" });
refetch(); // чекаємо відповідь від сервера, потім оновлюємо UI
}Мінуси:
- Кнопку «лайк» натиснуто → але UI не змінився, поки не прийшла відповідь.
- Користувач відчуває затримку 300-500 мс (або більше при поганій мережі).
- Відчувається "загальмований" застосунок.
Приклад з optimistic update:
const queryClient = useQueryClient();
async function handleLike(postId) {
// 1. Одразу оновлюємо UI локально
queryClient.setQueryData(['post', postId], (old) => ({
...old,
likes: old.likes + 1,
isLiked: true,
}));
try {
// 2. Надсилаємо запит на сервер
await fetch(`/api/posts/${postId}/like`, { method: 'POST' });
} catch (err) {
// 3. Якщо сервер відповів помилкою - відкочуємо зміни
queryClient.invalidateQueries(['post', postId]);
}
}Користувач бачить оновлення миттєво - навіть без відповіді від сервера. Коли сервер підтвердить - усе вже синхронізовано. Якщо сервер відповість помилкою - дані відкочуються до актуального стану.
Візуальний сценарій
| Подія | Що бачить користувач | Що відбувається в коді |
|---|---|---|
| Натиснув кнопку "лайк" | лайк став активним | setQueryData() оновлює кеш негайно |
| Сервер отримав запит | нічого не змінюється в UI | fetch() виконується у фоні |
| Сервер відповів 200 OK | усе залишається як є | кеш лишається актуальним |
| Сервер відповів 500 | лайк зникає | відкат (invalidateQueries або rollback) |
Чому це важливо
1. Миттєвий відгук
Користувач відчуває, що застосунок працює "у реальному часі"
- без затримок, навіть якщо мережа повільна.
2. Плавний UX
Інтерфейс реагує одразу, без "мерехтіння" лоадерів. Оптимістичні оновлення особливо важливі в інтерактивних діях:
- лайки,
- коментування,
- голосування,
- зміни імені, статусу, позиції елемента в списку.
3. Незалежність від мережі
Якщо запит не пройшов - можна відкотити локальні зміни. Користувач не втрачає контекст (він бачить, що дія "скасувалася").
Як реалізується на практиці
1. React Query
import { useMutation, useQueryClient } from '@tanstack/react-query';
function useLikePost() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (postId) => fetch(`/api/posts/${postId}/like`, { method: 'POST' }),
// 1. Оптимістично оновлюємо кеш
onMutate: async (postId) => {
await queryClient.cancelQueries(['post', postId]);
const prevPost = queryClient.getQueryData(['post', postId]);
queryClient.setQueryData(['post', postId], (old) => ({
...old,
likes: old.likes + 1,
isLiked: true,
}));
// 2. Повертаємо дані для rollback
return { prevPost };
},
// 3. Якщо помилка - відкочуємо
onError: (err, postId, context) => {
queryClient.setQueryData(['post', postId], context.prevPost);
},
// 4. Після успіху - оновлюємо або інвалідуємо
onSettled: (postId) => {
queryClient.invalidateQueries(['post', postId]);
},
});
}onMutate → локальне оновлення
onError → відкат
onSettled → фінальне оновлення/валідація
2. SWR (Vercel)
import useSWR, { mutate } from 'swr';
function likePost(postId) {
// оптимістично збільшуємо кількість лайків
mutate(`/api/posts/${postId}`, async (data) => {
await fetch(`/api/posts/${postId}/like`, { method: 'POST' });
return { ...data, likes: data.likes + 1, isLiked: true };
}, { optimisticData: { ...data, likes: data.likes + 1, isLiked: true }, rollbackOnError: true });
}3. Redux Toolkit Query
RTK Query також дозволяє тимчасово оновлювати кеш локально:
const [updatePost] = useUpdatePostMutation();
updatePost(newData)
.unwrap()
.then(() => dispatch(api.util.invalidateTags(['Post'])))
.catch(() => revertLocalState());4. Типові кейси для optimistic update
| Дія | Що оновлюємо локально |
|---|---|
| Лайк | Збільшуємо лічильник лайків |
| Додавання коментаря | Додаємо коментар у список |
| Видалення елемента | Видаляємо з UI до відповіді сервера |
| Зміна профілю | Змінюємо ім'я/аватар локально |
| Зміна порядку | Переставляємо елементи локально |
| Оплата / замовлення | Позначаємо "створено" до підтвердження сервера |
Підсумок
| Що робить Optimistic Update | Чому важливо |
|---|---|
| Оновлює UI до відповіді сервера | миттєвий відгук |
| Покращує UX і швидкість сприйняття | немає "затримки" при взаємодії |
| Синхронізується при успіху | UI і сервер лишаються узгодженими |
| Робить відкат при помилці | надійно при нестабільній мережі |
Скорочує кількість станів loading | інтерфейс відчувається "живим" |
Коротко:
Optimistic update - це спосіб зробити інтерфейс миттєво відгукливим: UI оновлюється відразу, оптимістично припускаючи успіх, а якщо сервер повернув помилку - React відкочує зміни.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.