Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Vue: Shared Composable vs Pinia

Дата публикации: 26-09-2026 19:10:59

Обсудим: composable, sharedComposable, pinia. Попробуем понять: а нужно ли вообще управлять состоянием? что значит управлять? кто должен управлять? и Какие существуют подводные камни в управлении состоянием. Методы и идеи их преодоления. Готовые библиотеки или примеры кода для использования.Контекст статьи — PWA, в других контекстах тоже будет работать, но это не точно.В статье будет критика Pinia. Если ты любишь этот инструмент, и не готов к конструктивной критике — лучше не читать, либо давай подискутируем в комментах. Я открыт к диалогу. Если ты уже думаешь о замене или уже ищешь её — это для тебя.  Читать далее

Основное содержимое страницы с новостью.

Уровень сложностиПростой

Время на прочтение5 мин

Охват и читатели7.2K

Мнение

Обсудим: composable, sharedComposable, pinia. Боли, кторые я испытал, когда использовал Pinia. Какие существуют подводные камни в управлении состоянием. Методы и идеи их преодоления. Альтернативы, готовые библиотеки.

Контекст статьи — PWA, в других контекстах тоже будет работать, но это не точно.

В статье будет критика Pinia. Если ты любишь этот инструмент, и не готов к конструктивной критике — лучше не читать, либо давай подискутируем в комментах. Я открыт к диалогу. Если ты уже думаешь о замене или уже ищешь её — это для тебя. 

Кратко по определениям

Composable — фабричная‑функция, которая создает объект для хранения состояния. Каждый вызов создает новый объект. Оф. документация рекомендует использовать Composable как замену миксинам. Это работает так:

  1. Компонент вызывает composable функцию.

  2. Она создает всегда новый объект, который хранит реактивное состояние в контексте компонента.

  3. Компонент использует объект, его свойства, методы, меняет состояние.

  4. При уничтожении компонента контекст уничтожается вместе объектом и состоянием.

Основное назначение — переиспользование одинакового функционала и создание локального состояния в разных компонентах.

Shared Composable отличается от composable:

  1. Создает новый объект, но в отдельном реактивном контексте. Новый контекст не связан с вызывающим компонентом, это позволяет хранить объект после удаления компонента.

  2. Имеет счетчик вызовов. При вызове в компоненте счетчик увеличивается, при уничтожении компонента — уменьшается. Новый объект создается только, когда счетчик нулевой. Уничтожается, когда стал нулевым. В остальных случаях возвращается существующий.

Основное назначение — создание, использование общего состояния, пока оно необходимо хотя бы одной компоненте.

PInia — глобальный менеджер состояний. 

  1. Создает объект состояния во время первого к нему обращение и больше никогда не удаляет. Объект состояние создается в отдельном от компонента реактивном контексте.

  2. Автоматически восстанавливает состояние при использовании SSR.

Зачем, если есть Pinia?

Наверно…, если с Pinia нет проблем, то и не нужно. Но чем больше проект, сложнее связи состояний, бизнес логика и UX, тем больше подводных камней может показать Pinia. Особенно, если хочется переиспользовать бизнес-логику в другом проекте.

Вот мои боли:

  1. Store нужно очищать и удалять, если он не используется. Если этого не сделать, возможны неожиданные эффекты. Об этом нужно помнить. И даже здесь есть особенности:

    1. $dispose не удаляет состояние. При повторном использовании store его состояние будет восстановлено до предыдущего. Чтобы этого избежать, нужно удалить состояние вручную: delete pinia.state.value[store.$id]

    2. Очистка состояния - дополнительный однотипный код внутри компонент.

    3. Store может быть композицией нескольких store или зависеть от них. Pinia ничего не знает о композиции и зависимостях, поэтому стандартные методы очистки reset и dispose здесь не подходят. Придётся самостоятельно придумывать, как очищать. А теперь представьте: один из store, который часть композиции, используются в нескольких местах. Ну и ... как понять — что нужно очищать, а что нет?

    4. Изменение иерархии компонент может потребовать переноса очистки store в другое место, за этим нужно следить.

  2. Фабричные функции store в том виде, в котором они описаны в доке:

    1. Сильно усложняют навигацию в IDE. Никогда не попадешь на определение метода —только в return или интерфейс. Особенная боль, когда их много и они большие. 

    2. Выглядят как код начала 2000-x. Так писали, когда не было классов и TypeScript. В то время возможности языка для создания объектов и инкапсулирования были сильно ограничены. Самое печальное, на мой взгляд, что начинающие разработчики читают это и думают, что это нормально, так и надо. По‑моему, это деградация.

  3. defineStore не явно меняет интерфейс объекта, созданного фабричной функцией.

    1. Об этом нужно помнить, особенно, если использовать деструктуризацию свойств. 

    2. Если возникла необходимость composable сделать общим через defineStore, придется исправлять весь код, который его использовал, потому что интерфейс изменится. 

  4. Сложные конструкции из типов в TypeScript.

  5. Особенности при SSR. pinia.state.value хранит только то, что вернул публичный интерфейс объекта. Если после гидрации нужно манипулировать состоянием, то можно получить неожиданное поведение, потому что внутреннего состояния не существует. Здесь приходится придумывать разные костыли.

    1. Пример: store категорий имеет публичные интерфейсы для получения категорий в виде плоского списка, дерева и категорий по текущему URL. Все интерфейсы возвращают данные, построенные на основе одной внутренней структуры. Pinia всё сериализовала, не спрашивая нас. После восстановления состояния на клиенте PWA будет как минимум 2 проблемы:

      1. Все объекты в этих структурах будут разные, даже если у них одинаковый id, потому что они были сериализованы по отдельности. Будь к этому готов, если ты сравниваешь в коде объекты.

      2. Попытка манипулирования состоянием может вызвать непонятные ошибки, потому что истинное (внутреннее) состояние пустое и не было сериализовано.

  6. Pinia — это искуственная абстракция. Это отдельная библиотека, которая оборачивает реактивность Vue в какое‑то отдельное API, чтобы …. что? Зачем? Честно говоря, я не нашел внятного ответа на этот вопрос. Давайте поищем вместе в комментариях.

  7. Тестирование store — это отдельная история с композицией и плагинами.

Мой вывод: Pinia пытается решить много проблем и не решает ни одну до конца.

Почему Shared Composable (SC)?

Потому что закрывает 4 из 6 болей описанных выше:

  1. store не нужно очищать и удалять

    1. SC никак не связан с хранением состояния. SC больше похож на контейнер зависимостей, типа https://github.com/microsoft/tsyringe. Токеном доступа к зависимости является функция‑провайдер. Хранимый объект может содержать реактивное состояние, но это не обязательно.

    2. Объекты удаляются автоматически, если не используются. Поэтому нет проблем с композицией состояний и зависимостями: всё, что используется останется, остальное будет удалено.

    3. Нет дополнительного кода очистки. Меньше кода — меньше проблем и ошибок.

    4. Вместо composable можно всегда смело использовать SC. Объект будет удален, если не используется.

  2. Результат фабричной функции хранится как есть, без изменения интерфейса.

    1. Ничто не мешает использовать внутри фабричной функции new SomeClass. При таком подходе навигация по коду будет простой: вы будете попадать точно на определение метода или свойства в классе, а не куда‑то в return.

    2. Тип останется без изменений, нет сложных вычисляемых типов.

    3. Если у вас есть composable, его легко можно сделать общим, вообще не трогая код, который его использовал.

  3. Всё API — это одна функция, которая регистрирует фабричную функцию в контейнере и создает функцию‑провайдер. Но эта функция делает очень важную вещь — позволяет очень легко отделить логику и состояние от представления. 

Какие есть альтернативы?

Код создания SC не сложен, вы можете сами написать такую функцию, и всё заработает. Пример можно посмотреть здесь. 

Я рекомендую vue‑modeler, там есть DI, действия можно отменять, они имеют своё состояние и контоль ошибок, интеграция с SSR. Библиотека закрывает все боли, которые есть у PInia. Отдельная статься на Хабре здесь.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Компонент перерисовался. Почему? Пишем инструмент для Vue и трижды ломаем чужой прод07.223-09-2026
2Как писать стили в 2026: CSS Modules, CSS‑in‑JS, Tailwind и zero‑runtime010.8401-10-2026
3Почему архитектура важнее выбора стейт-менеджера в React08.3701-10-2026
4EventBus и CommandBus во frontend: когда прямых вызовов становится слишком много011.7230-09-2026
5«Интернета нет — а сайт работает»: как мы учили PWA замечать авиарежим на iPhone08.8229-09-2026
6О том, как я написал свой стейт‑менеджер09.1427-09-2026
7[Перевод] 10 браузерных API, заменяющих библиотеки, которые я раньше все время устанавливал09.3528-09-2026
8Кризис идентичности, или как Vue-разработчик мигрировал enterprise-проект на Angular 1809.9425-09-2026
9От localStorage к HttpOnly Cookie. Как меняется архитектура авторизации в SPA07.3424-09-2026
10Если UI плагинный, почему BFF монолитный?08.5301-10-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 6.44. Источник: habr.com.