State Management
Svelte: руны и stores
Svelte-команда пишет редактор маршрутов для службы доставки. Внутри одного компонента карты состояние выражено руной `$state`: точки маршрута, выбранный курьер, режим редактирования. Но статус смены курьера нужен и в шапке, и в боковой панели, и в модалке подтверждения. Локальная руна туда не дотянется. Тогда состояние выносится в store: writable-значение, на которое подписываются все три несвязанных компонента. Svelte даёт два уровня: руны для локального реактивного состояния и stores для общего.
- Локальное состояние компонента: режим формы, открытый аккордеон, текущий шаг визарда через $state
- Производные значения через $derived: итоговая сумма корзины, валидность формы, число выбранных строк
- Общее состояние между несвязанными компонентами через writable store: тема, текущий пользователь, тосты
- Команды на SvelteKit, разделяющие состояние страницы и глобальные stores приложения
- Интеграция store с внешними источниками: WebSocket-поток в readable store с подпиской
Предварительные знания
- Идея observable: значение, на изменения которого можно подписаться
- Понимание реактивности: при изменении источника зависимые значения пересчитываются
- Различие между локальным состоянием компонента и общим состоянием приложения
Руны: реактивное состояние компонента
Svelte 5 вводит руны - специальные функции-маркеры, которые сообщают компилятору о реактивности. Руна `$state` объявляет реактивное значение: его изменение точечно обновляет ту часть DOM, что от него зависит. В отличие от React, реактивность не требует хука и массива зависимостей - компилятор сам строит граф зависимостей на этапе сборки.
Руна `$derived` объявляет производное значение: doubled пересчитывается всякий раз, когда меняется count, без ручного указания зависимостей. Компилятор видит, что doubled читает count, и связывает их. Это наблюдаемая реактивность из прошлого урока, но встроенная в язык шаблона и оптимизированная на этапе компиляции.
Руны появились в Svelte 5 (релиз конца 2024 года). До них реактивность держалась на присваивании let и метке `$:`, что путало новичков. Руны сделали реактивное состояние явным: `$state` и `$derived` читаются как маркеры намерения.
Что делает руна `$state` в Svelte 5?
Stores: общее состояние
Руна `$state` живёт внутри одного компонента. Когда состояние нужно нескольким несвязанным компонентам, Svelte предлагает stores. Store это наблюдаемое значение с методами subscribe, set и update. writable создаёт изменяемый store, readable - доступный только для чтения, например обёртку над внешним источником данных.
Внутри компонента store читается через префикс `$`: запись `$theme` в шаблоне автоматически подписывается на store и отписывается при размонтировании. Это снимает ручное управление подпиской. Запись в `$theme` эквивалентна вызову set, что делает store удобным двусторонним каналом общего состояния.
readable принимает функцию старта, которая получает set и возвращает функцию очистки. Это идеальная обёртка для WebSocket или таймера: store сам подключается при первой подписке и отключается, когда подписчиков не осталось.
Зачем нужен store, если есть руна `$state`?
Когда руны, когда stores
Граница простая. Если состояние нужно одному компоненту и его потомкам через props - это `$state.` Если одно значение читают и меняют несколько несвязанных компонентов - это store. Руны оптимальны для локальной реактивности и производных, stores для пересечения границ компонентов и интеграции с внешними источниками.
| Свойство | Руны ($state, $derived) | Stores (writable, readable) |
|---|---|---|
| Область | Локально в компоненте | Общая между компонентами |
| Подписка | Автоматически компилятором | Через $ в шаблоне или subscribe вне него |
| Доступ вне компонента | Нет напрямую | Есть через subscribe, set, update |
| Производные | $derived | derived |
| Где уместно | Состояние одного компонента и его поддерева | Тема, пользователь, тосты, внешние потоки |
Руны и stores не конкурируют, а дополняют друг друга. В Svelte 5 их можно связывать: значение store читается в руну, а реактивное состояние оборачивается в store-подобный объект для общего доступа. Этот интероп - отдельная важная тема, которую подробно разбирает курс по Svelte вместе с паттернами SvelteKit.
Здесь дан обзор для сравнения с другими фреймворками: руны это локальная реактивность уровня сигналов, stores это наблюдаемые значения уровня общего состояния. Полный разбор API, интеропа и серверной загрузки данных идёт в курсе по Svelte.
Тема приложения (light/dark) переключается в настройках и влияет на шапку, контент и подвал - три несвязанных компонента. Что разумнее в Svelte?
Связь с другими темами
Этот урок даёт обзор. Полный разбор Svelte-инструментов идёт в профильном курсе:
- Stores и интероп рун в Svelte — Реальный код writable и readable, интероп рун и stores, паттерны SvelteKit разобраны в курсе по Svelte
- Observable и Proxy — Store Svelte это наблюдаемое значение с подпиской, прямое продолжение модели observable
Итог
- Svelte 5 вводит руны: $state объявляет реактивное состояние, $derived строит производные значения
- Руны покрывают локальное состояние компонента: компилятор отслеживает зависимости и обновляет DOM точечно
- Stores (writable, readable) решают задачу общего состояния между несвязанными компонентами
- Store это наблюдаемое значение с методами subscribe, set и update, доступное и вне компонентов
- Префикс $ в шаблоне автоматически подписывается на store и отписывается при размонтировании
- Руны для локального реактивного состояния, stores для общего, детали и интероп разбираются в курсе по Svelte
Связанные уроки
- sm-08-observable-proxy — Stores Svelte это наблюдаемые значения с подпиской, прямое продолжение модели observable из прошлого урока
- sv-32-stores-interop — Полный разбор stores, интеропа рун и stores и реальный код Svelte живут в курсе по Svelte