Оптимістичне оновлення — це стратегія, коли ми оновлюємо інтерфейс так, ніби запит на сервер вже пройшов успішно. Це створює відчуття миттєвої реакції.
Якщо сервер поверне помилку, ми повинні "відкотити" (rollback) зміни назад.
RTK Query має спеціальний колбек onQueryStarted для мутацій, який дозволяє маніпулювати кешем.
updateBoard: builder.mutation<void, BoardData>({
query: (board) => ({
url: 'board',
method: 'POST',
body: board,
}),
async onQueryStarted(board, { dispatch, queryFulfilled }) {
// 1. Оптимістичне оновлення кешу 'getBoard'
const patchResult = dispatch(
apiSlice.util.updateQueryData('getBoard', undefined, (draft) => {
// draft - це поточний стан кешу. Ми замінюємо його на нові дані (board).
// Оскільки це Immer, ми можемо просто присвоїти або мутувати.
Object.assign(draft, board);
})
);
try {
// 2. Чекаємо відповіді сервера
await queryFulfilled;
} catch {
// 3. Якщо помилка — відкочуємо зміни (undo)
patchResult.undo();
alert('Не вдалося зберегти зміни! Синхронізація не вдалася.');
}
},
}),
У нас гібридна система:
boardSlice оновлюється миттєво через діспатч moveTask.updateBoard(newState).onQueryStarted, ми також оновлюємо кеш RTK Query.Але чекайте... Якщо ми вже оновили boardSlice локально, навіщо нам оновлювати кеш RTK Query?
У нашому випадку, оскільки boardSlice є "джерелом правди" для UI, нам не обов'язково робити оптимістичне оновлення кешу RTK Query для відображення змін (бо ми і так їх бачимо з локального слайсу).
АЛЕ, це корисно для узгодженості даних. Якщо інші компоненти підписані на useGetBoardQuery, вони теж миттєво отримають оновлення.
Якщо сервер впав:
queryFulfilled кидає помилку.patchResult.undo() відкочує кеш RTK Query.boardSlice все ще має "невірні" дані (переміщену картку).Нам потрібно синхронізувати локальний слайс назад з кешем.
Ми можемо додати extraReducers в boardSlice, щоб слухати apiSlice.endpoints.updateBoard.matchRejected.
// ...
builder.addMatcher(
apiSlice.endpoints.updateBoard.matchRejected,
(state, action) => {
// Якщо мутація впала — можливо, варто перезапитати дані з сервера
// або якось повідомити користувача.
// Найпростіший варіант відкату: ми не знаємо попередній стан тут легко.
// Стратегія: Позначити стан як "out of sync" і форсувати refetch.
}
);
Складність синхронізації клієнтського і серверного стану — це вічна проблема. Саме тому підхід "Тільки RTK Query (без локального слайсу)" часто простіший, але він не дозволяє синхронних оновлень для drag-and-drop.
У більшості випадків для DnD ми просто ігноруємо помилки або показуємо "Toast" повідомлення, і при наступному завантаженні сторінки дані синхронізуються.
Ми створили потужну архітектуру:
Це база, на якій будуються такі гіганти як Trello, Jira чи Asana.
Інтеграція з RTK Query
Тепер зробимо наш додаток "живим". Ми будемо завантажувати початковий стан з сервера і відправляти зміни назад.
Тестування Redux
Однією з головних переваг Redux є те, що його надзвичайно легко тестувати. Оскільки більшість логіки (редюсери, селектори) — це чисті функції, для їх тестування навіть не потрібно запускати React.