Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Svelte 5: Runes и useOptimistic для оптимистичных обновлений корзины rollback

Svelte 5: Runes и useOptimistic для оптимистичных обновлений корзины rollback

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

    Как в Svelte 5 с Runes можно реализовать оптимистичные обновления для корзины покупок. Это решает проблему лагов при добавлении товаров - UI обновляется мгновенно, а сервер подтверждает позже. Если что-то пойдет не так, делаем rollback без боли.

    Под капотом useOptimistic из SvelteKit упрощает стейт-менеджмент, интегрируясь с runes. Получается чистый DX: меньше бойлерплейта, лучше Web Vitals. Показываю на примере корзины, где юзер добавляет айтем - и бац, он уже в списке, даже без ответа с бэка.

    Runes в Svelte 5: $state и $derived для корзины

    Runes - это киллер-фича Svelte 5, которая делает реактивность явной и мощной. Вместо скрытого стейта теперь $state для мутабельных данных, $derived для вычисляемых значений. В корзине это идеально: держим массив товаров в $state, а totalPrice - в $derived. На первый взгляд кажется просто, но под капотом runes компилируются в vanilla JS без overhead.

    Представьте: юзер кликает ‘добавить в корзину’, стейт обновляется синхронно, рендер летает. Без runes пришлось бы тащить stores или props drilling - это просто боль. А здесь код изящный, типизированный на TS. Давайте разберем базовый сетап.

    • $state для корзины: let cart = $state<Product[]>([]); - мутируем напрямую, Svelte сам трекает изменения.
    • $derived для итога: let total = $derived(cart.reduce((sum, item) => sum + item.price * item.qty, 0)); - реактивно пересчитывается.
    • $effect для сайд-эффектов: effect(() => { if (cart.length) saveToLocalStorage(cart); }); - запускается при изменениях.
    Свойство Runes Старый Svelte
    Реактивность Явная, компилируется в signal Implicit, через $:
    DX Меньше boilerplate Больше writable stores
    SSR Полная поддержка Частично

    Нюанс: в SSR $state инициализируется на сервере, hydrate на клиенте - никаких flickering.

    useOptimistic: мгновенные обновления без race conditions

    useOptimistic - хук из SvelteKit, который берет optimistic стейт и action. При клике на ‘добавить’ он сразу мутирует UI-стейт, параллельно шлет fetch на сервер. Если ответ ок - коммитим, если ошибка - rollback к предыдущему стейту. Это огонь для корзины: юзер видит товар instantly, LCP не страдает.

    Под капотом происходит магия: хук создает shadow state на основе текущего, апплайит update function. Fetch идет с {optimistic: true}, сервер возвращает реальный стейт. Нет нужды в сложных reducer’ах как в Redux. В Svelte 5 это идеально сочетается с runes - $state остается чистым.

    Вот короткий пример на TS:

    <script>
      interface Product { id: string; name: string; price: number; qty: number; }
      let cart = $state<Product[]>([]);
      
      async function addToCart(product: Product) {
        const update = (cart: Product[]) => [...cart, {...product, qty: 1}];
        const result = await useOptimistic(cart, update, async () => {
          const res = await fetch('/api/cart', { method: 'POST', body: JSON.stringify(product) });
          return res.json();
        });
        cart = result; // коммит или rollback
      }
    </script>
    
    • Первый аргумент: текущий стейт (наш $state cart).
    • Второй: updateFn - как изменить стейт оптимистично.
    • Третий: action - реальный fetch с сервером.

    Крутость в том, что рендер обновляется дважды: optimistic > confirmed.

    Rollback при ошибках: graceful handling

    Если сервер вернул 500 или товар out of stock - useOptimistic автоматически роллбэчит стейт. Никаких try/catch вручную, хук сам toast’ит ошибку или логирует. В корзине это спасает от ghost items: добавил 10 шт, сервер сказал ‘нет, только 5’ - qty корректируется плавно.

    Добавим error handling:

    function addToCart(product: Omit<Product, 'qty'>) {
      return useOptimistic(
        cart,
        (c) => [...c, { ...product, qty: 1 }],
        async () => {
          const res = await fetch('/api/cart', {
            method: 'POST',
            body: JSON.stringify(product)
          });
          if (!res.ok) throw new Error('Out of stock');
          return res.json();
        },
        { onError: (err) => toast.error(err.message) }
      );
    }
    
    Сценарий Без useOptimistic С useOptimistic
    Успех Двойной рендер Один seamless
    Ошибка Ручной rollback Авто + toast
    Network Блокировка UI Instant feedback

    Важно: updateFn должен быть pure - без мутаций, возвращать new state.

    Полный пример: корзина с SSR и runes

    Склеим все: page.svelte с корзиной, +page.server.ts для API. На сервере рендерим initial cart из cookies или DB. Клиент hydrate’ит runes, useOptimistic берет на себя updates. Бандл минимальный, нет hydration mismatch.

    Сервер:

    // +page.server.ts
    export async function load() {
      const cart = await getCartFromDB();
      return { cart };
    }
    
    export const actions = {
      default: async ({ request }) => {
        const form = await request.formData();
        // update DB
        return { success: true, cart: updatedCart };
      }
    };
    

    Клиент рендерит streamed, optimistic работает из коробки. Total derived обновляется reactive.

    • Преимущества: CLS = 0, FID низкий, SEO-friendly SSR.
    • Нюансы: Для сложных updates делай batching в updateFn.
    • Оптимизации: Memoize derived с $derived.by().

    В итоге корзина флайтит даже на 3G - чистая магия Svelte 5.

    Масштабирование: от корзины к сложным формам

    Это не только для cart - useOptimistic тащит likes, comments, infinite lists. С runes стейт глобальный без контекста, легко шарить между компонентами. DX на уровне: линтер happy, TS strict, бандл lean.

    Осталось за кадром: интеграция с TanStack Query для кэша, или WebSockets для real-time. Подумать стоит над custom runes для offline-first apps - Svelte 5 дает фундамент. Код красивый, производительный, готов к продакшену.

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

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

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

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

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

    Категории

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

    Контакты

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

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

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

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

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