State Management

Nano Stores

Сайт на Astro собирает островки из разных фреймворков: шапка на React, корзина на Vue, баннер на Svelte. Каждому островку нужно знать число товаров в корзине. Через стор React эти данные не расшарить: Vue-островок про React-контекст ничего не знает. Nano Stores задаёт вопрос: а что, если стор это просто атом в отдельном модуле, к которому одинаково подключаются и React, и Vue, и Svelte, и ванильный JS, а весит вся библиотека меньше килобайта.

  • Astro-сайты с островами из разных фреймворков, которым нужно общее состояние корзины или темы
  • Микрофронтенды: несколько приложений на одной странице делят авторизацию и настройки
  • Дизайн-системы и виджеты, встраиваемые в чужие страницы без привязки к React
  • Проекты с жёстким бюджетом на размер бандла, где важен каждый килобайт
  • Постепенная миграция между фреймворками, где состояние должно пережить смену слоя представления

Предварительные знания

  • Идея единого источника правды для общего состояния
  • Подписка на изменения через слушателя и отписка от неё
  • Базовое понимание того, что фреймворк это лишь слой представления над данными
  • Единый источник правды

Откуда взялись framework-agnostic атомы

Nano Stores создал Андрей Ситник, автор PostCSS и Autoprefixer, примерно в 2021 году. Замысел шёл от размера и независимости: стор должен весить сотни байт и не зависеть ни от одного UI-фреймворка, чтобы одни и те же данные могли читать React, Vue, Svelte, Preact и ванильный JS. Каждый стор это маленький атом со значением и списком подписчиков, а тонкие адаптеры подключают его к конкретному фреймворку. К 2026 году подход стал особенно заметен в экосистеме Astro, где острова из разных фреймворков на одной странице делят общее состояние именно через Nano Stores.

Атомы и карты как единицы состояния

Базовая единица в Nano Stores это atom: маленький стор для одного значения. Функция atom принимает начальное значение и возвращает объект с методами get и set, а также подпиской. Изменение идёт через set, чтение через get. Никаких провайдеров, никакой привязки к React: атом это обычный модуль.

Когда значений несколько и они логически связаны, удобнее map: стор-объект, у которого поля меняются по ключу через setKey. Это экономит лишние пересоздания: меняется одно поле, а подписчики на другие поля карты не дёргаются. По соглашению имена сторов начинают с символа доллара, чтобы отличать их от обычных значений.

Производные значения собирает computed: он берёт один или несколько сторов и вычисляет из них новое значение, которое само становится стором. Это аналог derived-состояния: цена с налогом считается из суммы корзины и пересчитывается, когда сумма меняется.

Чем map() отличается от atom() в Nano Stores?

Один стор для разных фреймворков

Ключевая идея в том, что сам стор ничего не знает о фреймворке. Он умеет хранить значение и оповещать подписчиков. Подключение к конкретному UI делают тонкие адаптеры. Для React это useStore из пакета nanostores/react, для Vue и Svelte свои хелперы. Один и тот же атом читается из всех них одновременно.

useStore подписывается на атом и перерисовывает компонент при изменении значения, а при размонтировании отписывается. Тот же `$theme` в Vue-компоненте читается через адаптер для Vue, в Svelte через автоподписку с символом доллара. Стор живёт в отдельном модуле, а слои представления лишь подключаются к нему.

Поскольку стор это обычный модуль, его можно тестировать без рендера компонентов: вызвать set, прочитать get, проверить подписку. Логика состояния отделена от UI, и это упрощает и тесты, и перенос между фреймворками.

Почему один и тот же стор Nano Stores может читаться из React, Vue и Svelte сразу?

Ниша 2026: Astro, микрофронтенды, кросс-фреймворк

Сильнее всего Nano Stores проявляется там, где на одной странице сосуществуют разные фреймворки. Главный пример это Astro с его островной архитектурой: статичная страница, а внутри интерактивные острова, каждый из которых может быть на своём фреймворке. Общее состояние между островами Astro рекомендует держать именно в Nano Stores, потому что стор переживает границу острова и фреймворка.

Похожая картина в микрофронтендах: несколько независимых приложений на одной странице делят авторизацию, тему, настройки. Стор размером в сотни байт не утяжеляет каждый микрофронтенд и не навязывает им общий фреймворк. Третий сценарий это постепенная миграция: при переезде с одного фреймворка на другой состояние в Nano Stores остаётся на месте, меняется только слой представления над ним.

СценарийПочему Nano Stores
Astro-островаСостояние переживает границу острова и фреймворка
МикрофронтендыСотни байт на стор, без навязанного общего фреймворка
Кросс-фреймворк виджетОдин атом читают React, Vue, Svelte, ванильный JS
Миграция фреймворкаДанные на месте, меняется только UI-слой
Жёсткий бюджет бандлаРазмер библиотеки порядка сотен байт

Когда всё приложение это один React без чужих фреймворков и без жёсткого лимита на бандл, перевес Nano Stores над Zustand или Jotai невелик. Их сила в независимости от фреймворка проявляется именно на стыке нескольких UI-слоёв, а не внутри одного.

В каком сценарии framework-agnostic природа Nano Stores даёт наибольшее преимущество?

Связь с другими темами

Этот урок про framework-agnostic состояние. Рядом стоят соседи:

  • Единый источник правды — Nano Stores это один источник правды, который переживает границу между фреймворками
  • Лёгкие сторы: сравнение — Nano Stores сравнивается с Zustand, Jotai и Valtio по размеру бандла и модели
  • Zustand — Zustand привязан к React-хукам, Nano Stores независим от фреймворка - это и есть водораздел

Итог

  • Nano Stores это крошечные атомы со значением и подписчиками, библиотека весит порядка сотен байт
  • Стор не привязан ни к одному фреймворку: к нему подключаются React, Vue, Svelte, Preact и ванильный JS
  • atom() хранит одно значение, map() удобен для объекта полей, computed() выводит производное значение
  • Подписка через listen и subscribe, в React через useStore из адаптера nanostores/react
  • Главная ниша 2026 года: Astro-острова, микрофронтенды и общее состояние между разными фреймворками
  • Автор Андрей Ситник делал ставку на минимальный размер и независимость от UI-слоя

Связанные уроки

  • sm-03-single-source-of-truth — Nano Stores это единый источник правды, общий для нескольких фреймворков сразу
  • sm-21-lightweight-comparison — Nano Stores сравнивается с Zustand, Jotai и Valtio по размеру и ментальной модели
  • rc-38-zustand-state — Zustand живёт внутри React, а Nano Stores работает независимо от фреймворка, и это ключевое отличие
Nano Stores

0

1

Войти