Stately

@xstate/store-vue

The @xstate/store-vue package provides Vue bindings for XState Store. It includes composables for subscribing to store state as readonly refs, creating setup-scoped stores, and using atoms.

These are the docs for @xstate/store-vue v2. For v1 docs, see v1 docs.

This package re-exports all of @xstate/store, so you only need to install @xstate/store-vue.

Installation

npm install @xstate/store-vue
pnpm install @xstate/store-vue
yarn add @xstate/store-vue

Quick start

<script setup lang="ts">
import { createStore, useSelector } from '@xstate/store-vue'; 

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (context, event: { by?: number }) => ({
      count: context.count + (event.by ?? 1),
    }),
  },
});

const count = useSelector(store, (state) => state.context.count);
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="store.trigger.inc()">+1</button>
    <button @click="store.trigger.inc({ by: 5 })">+5</button>
  </div>
</template>

API

useSelector(store, selector?, compare?)

Creates a readonly ref that subscribes to a store or atom and returns a selected value.

useStore(configOrLogic, input?)

Creates a store instance for the current setup scope. Pass either a store config or store logic created with createStoreLogic(...).

<script setup lang="ts">
import { createStoreLogic, useSelector, useStore } from '@xstate/store-vue'; 

const counterLogic = createStoreLogic({
  context: (input: { initialCount: number }) => ({
    count: input.initialCount,
  }),
  on: {
    inc: (context) => ({ count: context.count + 1 }),
  },
});

const store = useStore(counterLogic, { initialCount: 0 });
const count = useSelector(store, (state) => state.context.count);
</script>

<template>
  <button @click="store.trigger.inc()">{{ count }}</button>
</template>

useAtom(atomOrConfig, selectorOrInput?, compare?)

Subscribes to an atom and returns a readonly ref. You can pass an existing atom, or an atom config created with createAtomConfig(...).

<script setup lang="ts">
import { createAtomConfig, useAtom } from '@xstate/store-vue'; 

const countConfig = createAtomConfig((input: { initialCount: number }) => {
  return input.initialCount;
});

const count = useAtom(countConfig, { initialCount: 0 });
</script>

<template>
  <div>Count: {{ count }}</div>
</template>

useAtomState(atomOrConfig, input?)

Creates or subscribes to an atom for the current setup scope. It returns the current readonly ref and the live atom instance.

<script setup lang="ts">
import { createAtomConfig, useAtomState } from '@xstate/store-vue'; 

const countConfig = createAtomConfig((input: { initialCount: number }) => {
  return input.initialCount;
});

const [count, countAtom] = useAtomState(countConfig, { initialCount: 0 });
</script>

<template>
  <button @click="countAtom.set((count) => count + 1)">
    {{ count }}
  </button>
</template>

Full documentation

For complete XState Store documentation including context, transitions, effects, atoms, and more, see the XState Store docs.

On this page