Общий доступ и инструменты
Общий доступ к машине между компонентами
useSharedMachine(config, options?) создаёт или получает singleton-инстанс машины по config.id. Полезно, когда несвязанным компонентам нужно делить одну и ту же запущенную машину без прокидывания пропсов или Pinia.
function useSharedMachine<TState, TEvent, TContext>(
config: MachineConfig<TState, TEvent, TContext>,
options?: UseMachineOptions,
): MachineInstance<TState, TEvent, TContext>Требует установленный VueMachinePlugin.
// В компоненте A
const { state } = useSharedMachine(cartMachine)
// В компоненте B (полностью отдельное дерево)
const { send } = useSharedMachine(cartMachine)
// Оба используют один и тот же инстанс машины — одно состояние, один контекст
await send('ADD_ITEM') // state.value компонента A обновляется реактивноЕсли машина с config.id уже зарегистрирована в хранилище, возвращается существующий инстанс (при этом внутренний счётчик ссылок хранилища для этого id увеличивается — см. Прямой доступ к хранилищу). Иначе создаётся новый и регистрируется автоматически.
Заметка: свои
options(включаяpersist) применяет только первый вызовuseSharedMachine(config, options)для данного id — каждый последующий вызов в любом другом месте дерева получает то, что настроил первый вызывающий, независимо от того, что передаёт он сам. В разработке, еслиoptionsпоследующего вызова заметно отличаются от тех, с которыми был реально создан общий инстанс (historyLimit, либоpersist.key/persist.storage), в консоль выводитсяconsole.warn, чтобы расхождение не осталось незамеченным — но собственныеoptionsпоследующего вызова всё равно молча игнорируются.
Vue-плагин
Установите VueMachinePlugin, чтобы включить глобальный реестр машин (useMachineStore, useSharedMachine) и интеграцию с DevTools.
import { createApp } from 'vue'
import { VueMachinePlugin } from '@macrulez/vue-state-machine'
import App from './App.vue'
const app = createApp(App)
app.use(VueMachinePlugin)
app.mount('#app')Прямой доступ к хранилищу
useMachineStore() предоставляет прямой доступ к глобальному реестру. Полезно для отладки или админ-панелей.
const store = useMachineStore()
store.register('cart', instance) // зарегистрировать вручную (опционально: register('cart', instance, options))
store.retain('cart') // отметить ещё одного пользователя уже зарегистрированного id, не заменяя его
store.unregister('cart') // освободить одно использование; запись реально удаляется только когда каждому register()/retain() найдётся парный unregister()
store.get('cart') // MachineInstance | undefined
store.getOptions('cart') // UseMachineOptions, с которыми был реально создан текущий инстанс, либо undefined
store.getAll() // Map<string, MachineInstance>Вызов useMachineStore() без установленного плагина выбрасывает содержательную ошибку.
Хранилище ведёт подсчёт ссылок: register() и retain() каждый увеличивают внутренний счётчик для id, а unregister() уменьшает его, реально удаляя запись только когда счётчик достигает нуля. useMachine() (а следовательно и useWizard(), построенный поверх него) автоматически вызывает store.unregister(id) в onUnmounted, а useSharedMachine() делает то же самое для каждого вызывающего, который переиспользует существующую запись через retain() — поэтому машина, общая для нескольких компонентов через один id, живёт, пока не размонтируется каждый из использующих её компонентов, а не только тот, что создал её первым. Если вы вызываете store.register() самостоятельно, в обход этих composable-функций, вы сами отвечаете за парный вызов store.unregister().
Заметка: в разработке
store.register(id, ...)выводитconsole.warn, еслиidуже зарегистрирован — обычно это значит, что два вызоваdefineMachine()/useMachine()(либо явныйWizardOptions.id) непреднамеренно используют один и тот же id. Прежний инстанс всё равно перезаписывается в любом случае; предупреждение — это только видимость проблемы, не защита от неё.
DevTools
Интеграция с DevTools живёт в отдельной точке входа, поэтому никогда не попадает в продакшен-бандлы.
import { createApp } from 'vue'
import { VueMachinePlugin } from '@macrulez/vue-state-machine'
import { VueMachineDevtools } from '@macrulez/vue-state-machine/devtools'
import App from './App.vue'
const app = createApp(App)
app.use(VueMachinePlugin)
// Только в разработке
if (import.meta.env.DEV) {
app.use(VueMachineDevtools)
}
app.mount('#app')Возможности панели:
- Регистрирует панель настроек «State Machines» в Vue DevTools
- При каждом обновлении инспектора DevTools (
visitComponentTree) отправляет одно событие таймлайна на каждую зарегистрированную машину (изMachineStore) с её текущим состоянием и контекстом — это живой снапшот, снимаемый при каждой инспекции дерева DevTools, а не push на каждый отдельныйsend(); переход, произошедший между двумя инспекциями, сам по себе не фиксируется
VueMachinePluginдолжен быть установлен раньшеVueMachineDevtools— он ищет хранилище черезapp._context.providesи предупреждает (не выбрасывает исключение), если плагин ещё не установлен.