Registry stores

Уточнения по работе реестра со сторами и их расширению

Utils

Утилиты берут инстанс pinia из RegistryContext.$pinia, инжект pinia происходит в nuxt модуле

useStoreWrapper

Полный аналог useRegistryWrapper, но в качестве второго аргумента передается DefineStoreOptions

useStoreSetupWrapper

Идентично useStoreWrapper, но для setup функций сторов.

defineRegistryStore

Полный аналог defineRegistryItem, но в качестве второго аргумента передается DefineStoreOptions

defineRegistrySetupStore

Идентично defineRegistryStore, но для setup функций сторов.

defineDefaultStore

Утилита сугубо для более простой типизации DefineStoreOptions, возвращает переданный аргумент без изменений

extendStore

Утилита для мержа двух DefineStoreOptions, приоритет за вторым аргументом

extendSetupStore

Схоже с extendStore, но для setup функций сторов.

Не стоит заменять состояние из исходного стора, т.к. исходная setup функция может на него полагаться

Usage

Шаг 1 (Описание зависимости)

Т.к. pinia store сложнее обычных зависимостей, приходится тщательнее типизировать код

import {
  type ExtractId,
  type ExtractState,
  type ExtractGetters,
  type ExtractActions,
  type StoreRegistryKey,
  defineDefaultStore,
  useStoreWrapper,

  setActiveRegistry,
} from '@/modules/registry';


// Хелпер сугубо для правильной типизации
// т.к. если нужен стор в shared, у него есть какое-то изначальное наполнение
// мы задаём это самое дефолтное хранилище которое опционально в дальнейшем
// можно расширить в проектах
export const defaultStore = defineDefaultStore({
  id: 'example',

  state: () => ({
    foo: 'foo',
    bar: 123,
  }),

  getters: {
    fooBar(state) {
      return state.foo + state.bar;
    },
  },
});


// Шаблонный код для дальнейшего расширения типов
export type Id = ExtractId<typeof defaultStore>;
export interface State extends ExtractState<typeof defaultStore> {}
export interface Getters extends ExtractGetters<typeof defaultStore> {}
export interface Actions extends ExtractActions<typeof defaultStore> {}


// StoreRegistryKey легкий алиас для RegistryKey<Store<...>>
export const injectionKey = `store:${defaultStore.id}` as unknown as StoreRegistryKey<Id, State, Getters, Actions>;

export default useStoreWrapper<Id, State, Getters, Actions>(injectionKey, defaultStore);
// Идентично
const useStore = defineStore(defaultStore);
export default (registry?: Registry) =>
  useRegistryItem(injectionKey, registry, ({ $pinia }, resolvedRegistry) => {
    setActiveRegistry(resolvedRegistry);

    return useStore($pinia);
  });

Шаг 1.1 (Setup описание)

import {
  type ExtractSetupState,
  type ExtractSetupGetters,
  type ExtractSetupActions,
  type StoreRegistryKey,
  useSetupStoreWrapper,
} from '@/modules/registry';


export const storeId = 'example';
export const defaultSetup = () => {
  const foo = ref('foo');

  const update = () => {
    foo.value = 'bar';
  };

  return {
    foo,

    update,
  };
};


export type Id = typeof storeId;
export interface State extends ExtractSetupState<ReturnType<typeof defaultSetup>> {}
export interface Getters extends ExtractSetupGetters<ReturnType<typeof defaultSetup>> {}
export interface Actions extends ExtractSetupActions<ReturnType<typeof defaultSetup>> {}


export const injectionKey = `store:${storeId}` as unknown as StoreRegistryKey<Id, State, Getters, Actions>;

export default useSetupStoreWrapper<Id, ReturnType<typeof defaultSetup>, State, Getters, Actions>(injectionKey, storeId, defaultSetup);

Шаг 2 (Реализация зависимости)

// registry/stores/example.ts
import { injectionKey, defaultStore } from '@/registry/stores/example';
import {
  defineRegistryStore,
  extendStore,
  setActiveRegistry,
  type ExtractState,
  type ExtractGetters,
  type ExtractActions,
} from '@/modules/registry';

// Расширение defaultStore
const extendedStore = extendStore(defaultStore, {
  state: (prevState) => ({
    ...prevState,
    baz: 'baz',
  }),

  getters: {
    barBaz (state) {
      return state.bar + state.baz;
    },
  },

  actions: {
    someActionInAnotherStore () {
      const anotherStore = useAnotherRegistryStore(this.$registry);
    },
  },
});

// Шаблонный код для расширения типов
declare module 'shared-front/lib/registry/stores/example' {
  interface State extends ExtractState<typeof extendedStore> {}
  interface Getters extends ExtractGetters<typeof extendedStore> {}
  interface Actions extends ExtractActions<typeof extendedStore> {}
}

export default defineRegistryStore(injectionKey, extendStore);
// Идентично
const useStore = defineStore(extendedStore);
export default defineRegistryItem(injectionKey, ({ $pinia }, registry) => {
  setActiveRegistry(registry);

  return useStore($pinia);
});

Шаг 2.1 (Setup реализация)

// registry/stores/example.ts
import { injectionKey, storeId, defaultSetup } from '@/registry/stores/example';
import {
  defineRegistrySetupStore,
  extendSetupStore,
  type ExtractSetupState,
  type ExtractSetupGetters,
  type ExtractSetupActions,
} from '@/modules/registry';


const extendedSetup = extendSetupStore((exampleStore) => {
  const uppercasedFoo = computed(() => {
    return exampleStore.foo.value.toUpperCase()
  });

  return {
    ...exampleStore,
    uppercasedFoo,
  };
}, defaultSetup);

declare module 'shared-front/lib/registry/stores/example' {
  interface State extends ExtractSetupState<ReturnType<typeof extendedSetup>> {}
  interface Getters extends ExtractSetupGetters<ReturnType<typeof extendedSetup>> {}
  interface Actions extends ExtractSetupActions<ReturnType<typeof extendedSetup>> {}
}

export default defineRegistrySetupStore(injectionKey, storeId, extendedSetup);

Не стоит заменять состояние из исходного стора, т.к. исходная setup функция может на него полагаться

Шаг 3 (Provide зависимости)

Без изменений

Шаг 4 (Использование зависимости)

В основном без изменений

Импорта другого pinia store реестра из текущего.

export default {
  ...
  actions: {
    async getExample() {
      const exampleStore = useExampleStore();

      await exampleStore.someAction();

      // После первого await небходимо явно указывать реестр
      const anotherStore = useAnotherStore(this.$registry);
    },
  },
  ...
}