Оптимистичные обновления в Next.js RSC — штука красивая, но с подводными: как не сломат...
Оптимистичные обновления в Next.js RSC — штука красивая, но с подводными: как не сломать UX на границе сервера и клиента Смотри, идея простая: ты дергаешь серверный экшен, а UI обновляется сразу, не дожидаясь ответа. Раньше это требовало дублирования логики на клиенте и сервере, сегодня, с useOptimistic из React 19 и Suspense-границами, можно сделать чисто. Но на практике многие забывают согласовать optimistic state с серверным ответом — и получают рассинхрон. Проблема: потеря данных при параллельных мутациях Если пользователь быстро отправляет два запроса подряд, optimistic update может перезаписать данные, еще не подтвержденные первым. Чтобы этого избежать, используйте идемпотентные ключи и очередь экшенов. const action = async (prevState, formData) => { const tempId = crypto.randomUUID(); addOptimistic({ id: tempId, text: formData.get('text'), pending: true }); const result = await api.update(formData); if (!result.ok) { rollbackOptimistic(tempId); // кастомный rollback return { error: result.error }; } // Сервер сам управляет состоянием }; Trade-off: Suspense как ловушка для пользователя Обернув список в <Suspense> при сбое, вы рискуете показать бесконечный fallback. Решение — задать минимальный таймаут для отката: <Suspense fallback={<Loading />}> <List items={optimisticState} /> </Suspense> Если сервер не ответил за 3 секунды, принудительно откатывайте оптимистичное состояние и показывайте ошибку. Где пригодится на практике * Лайки и комментарии в соцсетях. * Корзина интернет-магазина. * Инлайн-редактирование полей профиля. * Drag-and-drop с сохранением порядка. Ключевое: сервер остается source of truth, клиент не раздувается лишним состоянием, UX перестает тормозить на ровном месте. Вывод: Оптимистичные обновления эффективны только при явной синхронизации optimistic state с серверным ответом и грамотной обработке ошибок через Suspense-границы — иначе пользователь видит призрачные данные, которых не существует.