A lightweight, nearly drop-in replacement for Vuex.
npm i vue-stator --save
See documentation for Vue.js or Nuxt.js.
Stator is the stationary part of the rotary system - thanks to @pimlie for the awesome name suggestion.
vue-stator
uses Vue.observable()
under the hood, which means assignments and
Array changes will automatically trigger updates. So instead of actions and
mutations, vue-stator
only lets you define actions. To make transition
from Vuex easy, it introduces a new function signature for actions that help
making them look like mutations if needed.
Say you have a store/actions.js
file defining global actions:
export function myAction ({ state, actions }, param) {
state.param = param // mutates!
actions.otherAction()
}
export function otherAction ({ state }, param) {
state.paramDoubled = param * 2 // mutates!
}
The first argument is the local module context, the store object itself (and root state/getters/actions) is accessible
from the this
value within the action. This means that if you need to access the
global $state
, $actions
or $getters
you can access them using eg this.$state
vue-stator
introduces the possibility of having a unified state object.
Instead of shuffling across subdirectories looking for different state
definitions, you could now have a single place to look at: store/state.js
.
Still, the ability to group actions and getters by a key
is convenient.
vue-stator
fully supports module syntax which can define their own state, getters
and/or actions.
In practice, this just means you can define module actions where the first argument is a context object containing:
- state: the state for the current vue-stator module or the root state
- getter: the getters for the current vue-stator module or the root getters
- actions: the actions for the current vue-stator module or the root actions
import { plugin as VueStator } from 'vue-stator'
Vue.use(VueStator, {
state: () => ({
rootKey: 'a',
auth: {
user: null,
loggedIn: false
}
}),
modules: {
auth: {
actions: {
login ({ state }, user) {
state.user = user
state.loggedIn = false
this.$state.rootKey = 'b'
}
}
}
}
}
Again notice how state
is a direct reference to $state.auth
, to recap:
- The
state
property of the first argument is the state key that matches the module namespace this.$state
is the the root state
In Nuxt.js if you need to access properties from the Nuxt content (e.g. $axios or $http),
then you need to provide the inject
module option in your nuxt.config
. See
our Nuxt.js docs for more information
Beware: in Vuex, dispatching actions will always return a
Promise
.In
vue-stator
, that's optional. If you have code that expects an action to return a Promise (by following it with.then()
, for instance), make sure to returnPromise.resolve()
instead. Or, you can also simply switch toasync/await
syntax and it will work just fine.
vue-stator
also has vue devtools integration. You can pass devtools: false
as store option if you want to disable this. By default the value of Vue.config.devtools is used (which is false in production)
Due to differences between Vuex and vue-stator there are some remarks:
- reverting to a previous state doesnt reset newly added keys after that state
- getters are shown as an object tree of the modules you use
import { mapState, mapActions, mapGetters } from 'vue-stator'
vue-stator
packs mapState
, mapActions
and mapGetters
, which accept a
dictionary of method mappings, eg (['method', 'module/namespace/method'])
You have access to everything directly in Vue's context though.
That is, you can just reference $state.something
in your Vue template and it'll work.
You can enable a mixin helper by passing { mixin: true }
to your plugin options. Instead of calling mapState
etc in your components you can now just add a statorMap
option in your component:
// App.vue
Vue.use(VueStator, { mixin: true })
// my-component.vue
<script>
export default {
statorMap: {
// omitting the namespace is the default behaviour
// set this to false if you dont want to omit the namespace,
// then the properties will be available as: this['my/module/nonAliasedKey']
//omitNamespace: true,
state: {
my: {
module: {
nonAliasedKey: true,
aliasedKey: 'theModuleKey'
}
},
getters: [
'rootGetter',
'my/module/myGetter'
],
actions: ['myAction']
},
mounted () {
this.nonAliasedKey
this.aliasedKey
this.rootGetter
this.myGetter
this.myAction()
}
}
</script>
You can also use a function for statorMap
in case you need to eg map different state for eg Server-side or Client-side
statorMap() {
if (process.client) {
return { ... }
}
return { ... }
}
vue-stator
also provides some helper methods to interact with the store more easily.
-
$stator.subscribe('module/key', callback)
To quickly subscribe to specific state updates. This usesVue.$watch
under the hood -
$stator.registerModule(module, moduleName)
To dynamically register a store module. The moduleName can be ommitted if your module already contains a name property -
$stator.unregisterModule(moduleName)
To dynamically unregister a store module
beforeCreate () {
this.$stator.registerModule({
name: 'my/module',
state () {
return {
key: true
}
}
})
// or
this.$stator.registerModule({
state () {
return {
key: true
}
}
}, 'my/module')
},
mounted () {
this.$state.my.module.key // true
},
destroyed () {
this.$stator.unregisterModule('my/module')
}
In a further effort to make transition from Vuex, modularized getters are available in a similar fashion. The arguments passed to getter functions have the exact same signature as Vuex.
import { plugin as VueStator } from 'vue-stator'
Vue.use(VueStator, {
state: () => ({
user: {
firstName: 'John',
lastName: 'Doe'
},
}),
modules: {
user: {
getters: {
isFirstNameValid: state => state.firstName.length > 0,
isLastNameValid: state => state.lastName.length > 0,
isValid: (_, getters) => getters.isFirstNameValid && getters.isLastNameValid,
fullName (state, getters, rootState, rootGetters) {
if (getters.isValid) {
return `${state.firstName} ${state.lastName}`
}
/* below is for example purposes only, you dont need to use the root keys here */
if (rootGetters.user.isFirstNameValid) {
return rootState.user.firstName
}
return state.lastName
}
}
}
}
}
If you need your state to always be comitted to a storage provider, vue-stator
provides a configuration option which will automatically store and restore that
state on changes
const statorConfiguration = {
storage: {
provider: {
getItem (key) {
// do something
},
setItem (key, value) {
// do something
}
},
namespaces: [
'key',
'module/key'
]
}
}
Or if you need to use multiple storage providers
const statorConfiguration = {
storage: [
{ // object syntax
provider () {
if (process.client) {
return window.localStorage
}
},
namespaces: [
'persistent-key',
'my/module/key'
]
},
[ // array syntax
window.sessionStorage, // this will probably fail on SSR, see object syntax
[ 'temp-key' ]
]
]
}
Nuxt v2.10+ is required unless you set the module option
baseDir
to something different thenstore
Using vue-stator with Nuxt.js is as easy as using it with Vuex: a store
will be automatically created by loading files placed in a conventional
locations, such as store/state.js
.
See full documentation for the Nuxt.js module here.