На сегодняшний день все стейт-менеджеры экосистемы Vue (изначально Vuex, впоследствии Pinia, на примере которой и будет рассмотрена проблема) предоставляют глобальное централизованное хранилище, привязанное к корню приложения. И это замечательно: думаю, практически каждый читатель пользовался бенефитами данного подхода, будь то доступ к стору на любом уровне вложенности или переиспользование данных между различными блоками страницы. Однако у текущей системы есть одно важное ограничение - глобальные модули Pinia стора не позволяют создавать независимые состояния для инстансов одного компонента/модуля. Приведу несколько примеров. Мы в YCLIENTS столкнулись с этой проблемой, когда пытались переиспользовать крупный и сложный модуль оплат между вкладками одного модального окна. В окне одновременно могут сосуществовать несколько инстансов модуля, состояния которых хранятся в сторе и должны быть полностью независимы друг от друга, что в разрез с концепцией единого глобального хранилища из Pinia. С похожей проблемой столкнулись пользователи Pinia на GitHub: Cуществуют кейсы, когда на одной странице необходимо отобразить несколько датагридов (к примеру, сравнение различных наборов данных). Таким образом, состояния деревьев компонентов каждого датагрида должны быть независимы друг от друга Также стоит отметить, что во frontend-разработке нет единых правил по работе со сторами. В них хранят совершенно разные по типу и объемам данные. Мне встречались проекты, где даже небольшие переиспользуемые компоненты/блоки имели свои сторы. В целом сторов становится всё больше — одним из трендов последнего времени является переход от единого монолита к работе с множеством маленьких, специализированных хранилищ (Pinia и Effector яркий тому пример). Всё это (тенденции индустрии и разнообразие подходов к работе со сторами) делает проблему значительно более актуальной. В комментариях под дискуссией сообщество (при содействии одного из мейнтенеров Pinia) предложило несколько решений (раз и два). Однако их все объединяет одна главная особенность — использование кастомного идентификатора для доступа к стору (в решениях выше это tableId или listViewId). Без идентификатора сторонние компоненты не смогут получить доступ к нужному модулю Pinia. Следовательно, необходимо реализовать механизм хранения и передачи кастомных идентификаторов (ведь подобных сторов может быть несколько) всем использующим данный модуль компонентам, в том числе компонентам-потомкам. Решив одну проблему, мы получили другую. Отдельного внимания заслуживает библиотека pinia-di. С ее помощью можно решить вышеописанную проблему, но представленный подход значительно сложнее подхода Pinia. Скорее всего, команде потребуется время на его изучение и внедрение. Фактически авторы предлагают новый синтаксис работы со стором, который во многом идет вразрез с главными преимуществами и принципами Pinia: простотой и доступностью. Кажется необходимо решение, которое будет больше похоже на оригинальный синтаксис. Pinia стор, привязанный к скоупу (или Pinia scoped стор). В данном случае скоупом (или областью видимости) является инстанс компонента, который первым в иерархии использовал данный стор. Все дочерние компоненты данного инстанса получают доступ к нужному стору автоматически, передача идентификатора скоупа происходит под капотом, разработчику не нужно продумывать этот механизм или менять стандартный подход к работе со сторами. При использовании модуля в параллельной иерархии создается новый, независимый стор, доступ к которому потомки также получат автоматически. В итоге в каждой иерархии будет использоваться свой отдельный стор (storeModuleName/3 и storeModuleName/6 на картинке выше), скоупом которого является инстанс инициализирующего компонента. Этого удалось добиться за счет двух важных концепций: Создание стора (вызов оригинального defineStore()) происходит в момент непосредственного использования, что позволяет привязаться к скоупу(инстансу компонента) Для передачи идентификатора компонентам скоупа используется provide/inject. При этом получение и отправка идентификатора происходят под капотом, внутри функции useStore Теперь перейдем к реализации. За основу взят source код функции defineStore. Типизация практически полностью скопирована из оригинала (Vue core team активно используют as и any, поэтому и я не стал их избегать). В комментарии добавлены пояснения по каждому важному шагу: Версия без комментариев Текущее решение работает как в Compotition API, так и в Options API (совместимо с  mapState, mapWritableState, mapGetters и mapActions). Сигнатура функции defineScopedStore полностью соответствует сигнатуре оригинальной defineStore. Обратите внимание на функцию provideInInstance. Если работаете только в Composition API или не пользуетесь map-функциями, лучше заменить её на стандартный provide. Проблема заключается в том, что currentInstance для provide сетится во время вызова setup-функции, а вызов некоторых map-функций(например, mapState) происходит перед вызовом setup. В итоге в некоторых map-функциях provide не работает, так как не может найти currentInstance. Пришлось передавать currentInstance напрямую Рассмотрим использование scoped-стора в продуктовом коде YCLIENTS на примере модуля оплаты. Первым шагом создадим модуль scoped стора recordPayment (синтаксис и набор опций полностью идентичны стандартному стору Pinia): Переходим к компонентам. Точкой входа в модуль оплаты является компонент VPayment.vue. Именно в нем впервые используется и инициируется scoped стор recordPayment: Дочерние компоненты (в данном примере компонент VPaymentLoyaltyMethod.vue) модуля VPayment.vue обращаются к стору recordPayment точно также, как если бы это был стандартный Pinia стор: Сам модуль оплаты используется в нескольких компонентах-вкладках одного модального окна. В итоге в каждой вкладке модального окна у модуля VPayment будет собственное, независимое состояние, к которому все компоненты модуля могут получить доступ автоматически. Как видно по коду, используется стандартный синтаксис Pinia, ничего нового. Для использования scoped-сторов команде нет необходимости менять устоявшиеся подходы. При этом сторы становятся более инкапсулированными и независимыми, что значительно расширяет их область применения и позволяет справиться с описанными выше проблемами. Текущее решение также не мешает нам использовать вложенные сторы, всё будет работать из коробки. Однако привязка к скоупу влечет за собой ряд ограничений. Scoped-сторы можно использовать только внутри компонентов или в функциях, вызываемых из компонентов. Нет инстанса компонента — нет скоупа — нет стора Умирает скоуп (unmount инстанса компонента в котором впервые был использован стор) — умирает и стор Для совместимости с map-функциями mapState, mapWritableState, mapGetters и mapActions пришлось использовать скрытый API инстанса компонента (currentInstance.provides). Но добиться совместимости с функцией mapStores так и не удалось Главный кейс применения — сосуществование на одной странице нескольких инстансов компонента/модуля со стором, состояния которых должны быть независимы. Приведу несколько примеров:  Крупный модуль, переиспользуемый между вкладки одного окна (пример из статьи) или же между несколькими табами в рамках одной страницы. Подходит любой модуль со стором, инстансы которого должны быть независимы (в нашем случае это модуль оплат) Несколько таблиц со сторами на странице (пример из дискуссии на GitHub) Фильтры. К примеру, если есть несколько наборов фильтров и у каждого из них своё уникальное состояние Сложный контролл, состояние которого хранится в сторе, переиспользуемый в разных частых страницы  Подходы Pinia подталкивают нас к созданию маленьких и узконаправленных сторов, в противовес массивным и многофукнциональным модулям из Vuex. Кроме того, смещается фокус с их привязки к глобальному контексту: если раньше инициализировать стор приходилось самостоятельно во время инита всего приложения, то теперь этот процесс происходит автоматически. Всё это отлично согласуется с концепцией scoped-сторов — узконаправленных, локальных сторов, привязанных к конкретному инстансу модуля.  Senior Frontend Developer. Techlead