Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Фронтенд
  4. React 19: useOptimistic для мгновенной корзины e-commerce с откатом ошибок

React 19: useOptimistic для мгновенной корзины e-commerce с откатом ошибок

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

    Обложка: React 19: useOptimistic с optimistic UI для мгновенных обновлений e-commerce корзины с автоматическим откатом при ошибках сети

    useOptimistic в React 19 - это киллер-фича для отзывчивых UI. Представь: юзер добавляет товар в корзину, и она обновляется мгновенно, без лагов от сетевых запросов. А если сервер отвалился - стейт откатывается автоматически. Идеально для e-commerce, где каждая миллисекунда на счету.

    Эта тема спасет от типичных болей: спиннеры на пол-экрана, фрустрация юзеров и убитые Core Web Vitals. Разберем на примере корзины - от базового сетапа до обработки ошибок. Код на TS, минимум бойлерплейта, максимум DX.

    Как работает useOptimistic под капотом

    useOptimistic берет твое реальное состояние и возвращает оптимистичную копию. Ты даешь ему редьюсер-функцию, которая говорит: “а что если действие сработает? Покажи это в UI”. Пока запрос висит, рендерится оптимистичный стейт. Сервер ответил - реальное состояние обновляется, и optimistic синхронизируется.

    В e-commerce это магия: добавь товар - корзина сразу показывает +1 итем, даже если API тормозит. Ключевой нюанс: хук завязан на реальный стейт как на source of truth. Ошибка? Реальный стейт не меняется - optimistic откатывается сам. Никаких ручных if’ов и try-catch хеллов.

    Это упрощает жизнь по сравнению с ручными optimistic updates в useState + useTransition. Вот базовая схема:

    • Первый аргумент: текущее реальное состояние (массив товаров корзины).
    • Второй аргумент: редьюсер (state, action) => optimisticState - здесь action это данные для обновления (новый товар).
    • Возврат: [optimisticState, updateFn] - рендерим optimisticState, вызываем updateFn перед запросом.
    Сравнение подходов useState + manual useOptimistic
    Код 20+ строк с loading/error 5 строк чистоты
    Откат ошибок Ручной Автоматический
    DX Боль Кайф

    Реальный пример: корзина с мгновенным добавлением

    Начнем с типичной корзины. У нас массив товаров, API-эндпоинт для добавления. Без useOptimistic юзер кликает “Добавить” - спиннер, 500мс лага, CLS прыгает. С хуком - товар появляется instantly, с меткой “Отправка…”.

    Код супер-изящный. Смотри, как это выглядит в компоненте Cart:

    import { useOptimistic } from 'react';
    
    type CartItem = { id: string; name: string; qty: number };
    
    type CartState = CartItem[];
    
    const addToCart = (state: CartState, newItem: CartItem): CartState => [
      ...state,
      { ...newItem, qty: 1, status: 'pending' as const }
    ];
    
    function Cart({ realCart }: { realCart: CartState }) {
      const [optimisticCart, addOptimisticItem] = useOptimistic(realCart, addToCart);
    
      const handleAdd = async (item: Omit<CartItem, 'qty' | 'status'>) => {
        const optimisticItem = { ...item, qty: 1, status: 'pending' };
        addOptimisticItem(optimisticItem);
    
        try {
          await fetch('/api/cart', { method: 'POST', body: JSON.stringify(item) });
          // Реальный стейт обновится через revalidation (Next.js) или внешний setter
        } catch {
          // Ничего не делаем - optimistic откатится сам
        }
      };
    
      return (
        <ul>
          {optimisticCart.map(item => (
            <li key={item.id}>
              {item.name} (x{item.qty})
              {item.status === 'pending' && ' ➤ Отправка...'}
            </li>
          ))}
        </ul>
      );
    }
    

    Видишь, как лаконично? handleAdd вызывает addOptimisticItem до fetch. UI мигнул - товар в списке. Сервер OK - реальный стейт апдейтится (через SWR/mutate или Next.js revalidate). Ошибка - optimisticCart синхронизируется с realCart автоматически.

    Плюсы этого подхода:

    • Мгновенный фидбек - LCP/FCP на высоте.
    • Автооткат - никаких race conditions.
    • Suspense-ready - работает с React 19 новыми фичами вроде use.

    Обработка ошибок и edge-кейсов

    Сетевые фейлы - классика e-commerce. useOptimistic бьет их одним выстрелом. Когда fetch падает, просто не трогай реальный стейт. Хук заметит расхождение и откатит optimistic к реальному.

    Более хитрый кейс: обновление количества. Юзер меняет qty с 1 на 5 - пока API думает, показываем 5. Ошибка? Откат к 1. Добавь статусы для granular контроля:

    type ItemStatus = 'idle' | 'pending' | 'error';
    
    const updateQty = (state: CartState, { id, qty }: { id: string; qty: number }) =>
      state.map(item =>
        item.id === id
          ? { ...item, qty, status: 'pending' }
          : item
      );
    

    Нюансы, которые спасут нервы:

    • Идемпотентность: делай action-данные уникальными (timestamp/id), чтоб избежать дублей.
    • Batch updates: несколько addToCart подряд? Хук их merge’ит умно.
    • Server errors: в редьюсере можно return fallback-state с уведомлением.
    Кейс Без хука С useOptimistic
    Add item + network fail Спиннер вечно Мгновенно + откат
    Update qty Ручной loading Авто
    Offline Полный ступор Оптимистично до reconnect

    Улучшение UX: статусы, удаление, оффлайн

    Расширим корзину. Добавим удаление и оффлайн-поддержку. useOptimistic идеален для этого - редьюсер может handle’ить разные action types.

    const cartReducer = (state: CartState, action: CartAction): CartState => {
      switch (action.type) {
        case 'ADD':
          return [...state, { ...action.payload, status: 'pending' }];
        case 'REMOVE':
          return state.filter(item => item.id !== action.id).map(item => ({ ...item, status: 'pending' }));
        default:
          return state;
      }
    };
    

    Теперь один хук - все операции. Оффлайн? Пока нет сети, UI отзывчивый. Reconnect - синхронизируется. Web Vitals взлетают: CLS=0, FID<10мс.

    • Удаление: миг - итем исчез, “Удаление…”. OK/откат.
    • Оффлайн-first: optimistic держит стейт, sync при online.
    • Accessibility: добавь aria-live для скринеров.

    useOptimistic + Next.js 15: прод-готовый стек

    В Next.js это вообще песня. С React Server Actions + revalidatePath/Promise хук интегрируется из коробки. App Router? Server Components фетчат realCart, клиентские - optimistic.

    'use server';
    export async function addToCartServer(item: CartItem) {
      // Server logic
      revalidatePath('/cart');
    }
    

    Клиент вызывает action, optimistic апдейт - DX на уровне. Производительность: SSR для initial, CSR optimistic для интерактива. Бандл минимальный, нет лишних useEffect.

    Почему это меняет e-commerce игру

    useOptimistic - не просто хук, а паттерн для future-proof UI. Корзина ощущается native-приложением: мгновенно, надежно, с грациозным откатом. Забудь про loading skeletons везде.

    Осталось доработать: интеграция с Zustand/Jotai для global state, тесты с MSW, A/B-тесты метрик. Подумай, как замиксовать с useFormStatus для форм чекаута - выйдет монстр отзывчивости.

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

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

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

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

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

    Категории

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

    Контакты

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

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

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

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

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