<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Svelte 5: Runes с useOptimistic и Zustand для оптимистичных уведомлений]]></title><description><![CDATA[<p dir="auto">В Svelte 5 руны меняют правила игры для стейта. Теперь с $state, $derived и $effect можно делать <strong>оптимистичные обновления</strong> уведомлений без лагов и лишнего рендера. Это решает боль медленных сетевых запросов - UI реагирует мгновенно, а откат при ошибке автоматический.</p>
<p dir="auto">Zustand как стейт-менеджер идеально вписывается в эту схему. Комбинируем руны с useOptimistic-подобным паттерном, и получаем киллер-фича для уведомлений: добавляем уведомление сразу, шлем на сервер, при фейле - роллбэк. DX на высоте, бандл лёгкий, Web Vitals в зелёной зоне.</p>
<h2>Почему руны в Svelte 5 - это будущее стейта</h2>
<p dir="auto">Руны в Svelte 5 - это сигналы под капотом, мелкозернистая реактивность без бойлерплейта. Забудьте про старый реактивный let, теперь $state создаёт чистый сигнал, который триггерит обновления только там, где нужно. Для уведомлений это идеально: список сообщений обновляется точечно, без полного ререндера компонента.</p>
<p dir="auto">Представьте: юзер шлёт уведомление, UI показывает его мгновенно с ‘отправка…’. Сервер отвечает - метка уходит, или при ошибке уведомление откатывается. Без рун пришлось бы мутировать массив вручную и следить за состоянием. С рунами и Zustand всё чисто: стейт иммутабельный, обновления предсказуемые. Это не просто фича - это оп��имизация производительности на уровне Solid.js.</p>
<ul>
<li><strong>$state для базового стейта</strong>: <code>let notifications = $state([]);</code> - массив уведомлений реактивный из коробки.</li>
<li><strong>$derived для вычислений</strong>: <code>const pendingCount = $derived(notifications.filter(n =&gt; n.status === 'pending').length);</code> - счётчик пендингов без лишних эффектов.</li>
<li><strong>$effect для сайд-эффектов</strong>: <code>$effect(() =&gt; { if (notifications.length &gt; 50) notifications.shift(); });</code> - автоочистка старых сообщений.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Аспект</th>
<th>Старый Svelte</th>
<th>Runes в Svelte 5</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Реактивность</strong></td>
<td>Глобальный трекинг</td>
<td>Мелкозернистая, сигналы</td>
</tr>
<tr>
<td><strong>Бойлерплейт</strong></td>
<td>export let</td>
<td>$props(), $state()</td>
</tr>
<tr>
<td><strong>Оптимизации</strong></td>
<td>Компилятор</td>
<td>+ Иммутабельность, точечный рендер</td>
</tr>
</tbody>
</table>
<p dir="auto"><em>Нюанс: руны работают и в .svelte, и в .js/.ts файлах - портируем стейт в Zustand без боли.</em></p>
<h2>Zustand + руны: глобальный стейт без Redux-кошмара</h2>
<p dir="auto">Zustand - лёгкая либа для стейта, без провайдеров и контекста. В Svelte 5 она идеально комбинируется с рунами: создаём стор с $state внутри, экспортируем хуки. Для уведомлений это win: один стор на все компоненты, атомарные обновления, никаких пропс-дриллов.</p>
<p dir="auto">Стор выглядит так: <code>const useNotificationsStore = create((set) =&gt; ({ notifications: $state([]), addOptimistic: (notif) =&gt; set((state) =&gt; { state.notifications.unshift({ ...notif, status: 'pending' }); }) }));</code>. Здесь addOptimistic - наш аналог React-хука, мутирует стейт оптимистично. Затем асинхронно шлём на API, при успехе обновляем статус, при ошибке - фильтруем из массива. Реактивность рун подхватывает изменения автоматически.</p>
<ol>
<li><strong>Инициализация стора</strong>: Импортируем Zustand, оборачиваем в $state для реактивности.</li>
<li><strong>Оптимистичный адд</strong>: Добавляем в начало списка с pending статусом.</li>
<li><strong>Асинхронный апдейт</strong>: fetch/post, затем set с реальным статусом или удалением.</li>
</ol>
<pre><code class="language-typescript">const useNotificationsStore = create((set, get) =&gt; ({
  notifications: $state([]),
  addOptimistic: async (text: string) =&gt; {
    const id = Date.now();
    set((state) =&gt; {
      state.notifications.unshift({ id, text, status: 'pending' });
    });
    try {
      await fetch('/api/notifications', { method: 'POST', body: JSON.stringify({ text }) });
      set((state) =&gt; {
        const idx = state.notifications.findIndex(n =&gt; n.id === id);
        if (idx &gt; -1) state.notifications[idx].status = 'sent';
      });
    } catch {
      set((state) =&gt; state.notifications = state.notifications.filter(n =&gt; n.id !== id));
    }
  }
}));
</code></pre>
<p dir="auto"><strong>Красота кода</strong>: Zustand не навязывает редьюсеры, руны обеспечивают гранулярные обновления. Бандл растёт минимально - Zustand всего 1кб.</p>
<h2>useOptimistic паттерн в Svelte: реализация на рунах</h2>
<p dir="auto">useOptimistic из React - хук для мгновенных UI-обновлений во время async. В Svelte 5 нет нативного, но с рунами и Zustand патчим сами. Логика: держим два слоя стейта - optimistic (с pending) и confirmed (с сервера). $derived сливает их в один список для рендера.</p>
<p dir="auto">Пример в компоненте: <code>function handleSend() { useNotificationsStore.getState().addOptimistic(inputValue); }</code>. UI показывает pending сразу, эффект в сторе обрабатывает откат. Это даёт отзывчивость как в Gmail - уведомление появляется до API-ответа. При ошибке роллбэк плавный, без мерцания.</p>
<ul>
<li><strong>Преимущества</strong>: Задержка воспринимается как 0мс, LCP/INP в топе Web Vitals.</li>
<li><strong>Ловушки</strong>: <em>Всегда валидируй на сервере - клиент optimistic.</em></li>
<li><strong>Расширение</strong>: Добавь $effect для WebSocket-реалтайм синка.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Сценарий</th>
<th>Без optimistic</th>
<th>С useOptimistic</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Add уведомления</strong></td>
<td>Ждёт API (500мс+)</td>
<td>Мгновенно + откат</td>
</tr>
<tr>
<td><strong>Рендер</strong></td>
<td>Полный ререндер</td>
<td>Точечный</td>
</tr>
<tr>
<td><strong>Ошибка</strong></td>
<td>Пустой список</td>
<td>Авто-роллбэк</td>
</tr>
</tbody>
</table>
<h2>Собираем пазл: уведомления с SSR и рунами</h2>
<p dir="auto">Для SSR в SvelteKit гидратируем стейт из Zustand - руны поддерживают серверный рендер из коробки. В +page.svelte: <code>let { notifications } = useNotificationsStore();</code>. При гидратации optimistic-логика работает seamless, без hydration mismatch.</p>
<p dir="auto">Код компонента уведомлений: простая таблица или список с {notifications.map(n =&gt; </p><div class="{n.status}">{n.text}</div>)}. Стилизуем pending как скелетон - юзер кайфует от скорости. Масштабируй на тысячи уведомлений - производительность не страдает.<p></p>
<h2>Такой подход меняет DX в Svelte</h2>
<p dir="auto">Руны + Zustand + optimistic - комбо для уведомлений, которое масштабируется на чат, туду, дашборды. Осталось за кадром: интеграция с TanStack Query для кэша, или кастомные $effect для оффлайн-режима. Подумай, как это впишется в твой стэк - бандл полетит, а юзеры скажут спасибо за скорость.</p>
]]></description><link>https://forum.exlends.ru/topic/1762/svelte-5-runes-s-useoptimistic-i-zustand-dlya-optimistichnyh-uvedomlenij</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:46:23 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1762.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 19 Mar 2026 12:25:35 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Svelte 5: Runes с useOptimistic и Zustand для оптимистичных уведомлений on Thu, 19 Mar 2026 12:29:40 GMT]]></title><description><![CDATA[<p dir="auto">Жесть какая-то, каждый день что-то обновляют. Вот честно я уже не то что не успеваю - я уже не хочу даже бежать за этими обновляшками, мне хватает порки с Nexst js…</p>
]]></description><link>https://forum.exlends.ru/post/2669</link><guid isPermaLink="true">https://forum.exlends.ru/post/2669</guid><dc:creator><![CDATA[kirilljsx]]></dc:creator><pubDate>Thu, 19 Mar 2026 12:29:40 GMT</pubDate></item></channel></rss>