Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Фронтенд
  4. React 19: useOptimistic + IndexedDB для offline-first синхронизации

React 19: useOptimistic + IndexedDB для offline-first синхронизации

Запланировано Прикреплена Закрыта Перенесена Фронтенд
react19useoptimisticindexeddb
1 Сообщения 1 Постеры 5 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал отредактировано
    #1

    Обложка: React 19: useOptimistic с offline-first стратегией и IndexedDB для синхронизации данных при восстановлении соединения

    React 19 приносит useOptimistic - хук, который делает optimistic UI нативным и без боли. С ним UI обновляется мгновенно, а синхронизация с сервером уходит в фон. Это киллер-фича для apps, где юзеры жмут кнопки оффлайн и не хотят ждать.

    Комбинируем с IndexedDB и получаем полноценную offline-first стратегию. Данные пишутся локально, очередь синка держится в БД, а при коннекте всё улетает на сервер. Никаких лоадеров, никаких ‘подождите’ - чистый DX и топ Web Vitals.

    useOptimistic: мгновенные обновления без бойлерплейта

    useOptimistic - это хук, который держит два стейта: базовый (с сервера) и optimistic (для моментального фидбека). Ты кидаешь обновление в optimistic слой, UI рендерится сразу, а реальный запрос уходит асинхронно. Если сервер ответил ок - база обновляется. Если фейл - откатываемся или реконсилируем.

    Представь туду-лист: юзер добавляет задачу оффлайн, список растет на глазах. В фоне данные ложатся в IndexedDB, optimistic стейт сияет. Сервер подтвердит - синк завершён, нет - конфликт решим last-write-wins. Это убирает тонну useState + useEffect + лоадеры.

    Ключевые плюсы:

    • Мгновенный рендер: UI не блокируется, CLS и FID на высоте.
    • Нативный роллбэк: React сам мерджит стейты, без ручного трэка.
    • Простота: один хук вместо кастомного стейт-менеджера.
    Сценарий Без useOptimistic С useOptimistic
    Add task оффлайн Локер + очередь Мгновенный UI + DB
    Синк при коннекте Ручной retry Авто-мердж
    Конфликт Самописный resolver Last-write-wins

    IndexedDB как локальный source of truth

    IndexedDB - это встроенная NoSQL БД в браузере, идеал для offline-first. Не путай с localStorage - тут транзакции, индексы, большой объём. Либы вроде dexie или idb упрощают API до уровня Firebase: openDB, add, getAll - и готово.

    В offline-first всегда читаем из IndexedDB первым. Сеть только для апдейта локалки. Пишем очередь операций в отдельный стор syncQueue с UUID, timestamp и status. Оффлайн-сущности генерят clientId, чтоб не ждать серверных ID. При коннекте worker или хук прогоняет очередь, обновляя optimistic стейт.

    Настройка базовая:

    import { openDB } from 'idb';
    
    const DB_NAME = 'offlineAppDB';
    const STORE_NAME = 'tasks';
    
    export const initDB = async () => {
      return openDB(DB_NAME, 1, {
        upgrade(db) {
          if (!db.objectStoreNames.contains(STORE_NAME)) {
            db.createObjectStore(STORE_NAME, { keyPath: 'clientId' });
          }
          if (!db.objectStoreNames.contains('syncQueue')) {
            db.createObjectStore('syncQueue', { keyPath: 'id', autoIncrement: true });
          }
        },
      });
    };
    
    export const queueSync = async (operation: any) => {
      const db = await initDB();
      await db.add('syncQueue', { ...operation, status: 'pending' });
    };
    

    Бест-практисы:

    • UUID для оффлайн-ID (не полагайся на сервер).
    • Версионинг: track updatedAt для конфликтов.
    • Queue survives restarts - IndexedDB persistent.

    Синхронизация: от optimistic к серверу

    Сердце offline-first - background sync. useOptimistic апдейтит UI, IndexedDB ловит данные, а синк-логик проверяет navigator.onLine и прогоняет очередь. Используй useEffect с event listener на ‘online’, или Service Worker для надёжности.

    Пример туду-хука:

    import { useOptimistic, useEffect } from 'react';
    
    function useOfflineTodos(initialTodos: Todo[]) {
      const [optimisticTodos, addOptimisticTodo] = useOptimistic(initialTodos, (state, newTodo: Todo) => [...state, newTodo]);
    
      const addTodo = (todo: Todo) => {
        addOptimisticTodo({ ...todo, clientId: crypto.randomUUID(), status: 'pending' });
        queueSync({ type: 'add', payload: todo });
      };
    
      useEffect(() => {
        const sync = async () => {
          if (navigator.onLine) {
            // прогоняем syncQueue, апдейтим optimisticTodos
          }
        };
        window.addEventListener('online', sync);
        return () => window.removeEventListener('online', sync);
      }, [optimisticTodos]);
    
      return { optimisticTodos, addTodo };
    }
    

    Шаги синка:

    1. Pending ops из syncQueue -> API calls батчем.
    2. Сервер OK? Update local DB + optimistic state.
    3. Error? Retry с экспоненциальной задержкой или mark ‘failed’.
    Status Action UI Effect
    pending API POST/PUT Песочинки/Spinner
    synced Mark done ✅ Иконка
    failed Retry queue ⚠️ Warning

    useOptimistic + IndexedDB в реальном туду-листе

    Склеиваем всё в компонент. useOptimistic держит стейт, кастом-хук - DB + sync. Оффлайн юзер добавляет/чекует тудушки - UI летает. Коннект - синк прозрачный, без ререндера всего списка.

    Полный пример:

    const TodoList = ({ initialTodos }: { initialTodos: Todo[] }) => {
      const { optimisticTodos, addTodo, toggleTodo } = useOfflineTodos(initialTodos);
    
      return (
        <div>
          <input onKeyDown={(e) => e.key === 'Enter' && addTodo({ title: e.currentTarget.value })} />
          <ul>
            {optimisticTodos.map(todo => (
              <li key={todo.clientId}>
                <input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.clientId)} />
                {todo.title} {todo.status === 'pending' && '⏳'}
              </li>
            ))}
          </ul>
        </div>
      );
    };
    

    Фичи в действии:

    • Optimistic toggle: чекбокс меняется до API.
    • IndexedDB как бэкап: refresh - данные на месте.
    • Конфликты: серверная версия > локальной - мерджим.

    Это даёт FCP <100ms даже оффлайн, LCP без задержек. Линтеры и TS happy - типы на строгом уровне.

    Код, который хочется клонировать

    Вместе useOptimistic и IndexedDB превращают рендер в шелк. Оффлайн больше не баг - это фича. Хочется копать глубже в conflict resolution или SW для пуши-нотификаций, но базис уже летает.

    Масштабируй на реальные apps: чаты, шопинг-корзины, формы. DX на уровне Next.js 15+, бандл минимальный - никаких внешних либ для стейта. React 19 реально меняет игру.

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы