v2.0.0-rc.1
Pre-releaseWasn't 1.0-rc just released?
Yes, the 1.0-rc is consolidating the current API in 0.8.x with very minor breaking changes and marking it as stable. Most current 0.8.x users should be able to easily migrate to 1.0 with minimal effort; However 2.0 introduces some more substantial changes and may not be an easy upgrade for 0.8.x users. We are releasing both in parallel - both will be maintained for bug fixes, the difference being that 1.0 is considered "done" and will not receive new features in the future.
Breaking Changes from 1.0
-
store.dispatch()
is now used for triggering actions instead of mutations. To trigger a mutation, use the newstore.commit()
method. (See Actions & Getters in the Store section below) -
store.dispatch()
andstore.commit()
are no longer variadic: it now accepts a single payload value as the second argument:store.dispatch('action', payload) store.commit('mutation', payload)
-
The
vuex
component option has been deprecated. (See Component Binding Helpers section for new component binding usage below) -
reverted in 2.0.0-rc.3store.watch
is deprecated. Usestore.subscribe
to react to mutations.
Breaking Changes from 0.8.x
-
middlewares
are replaced byplugins
. A plugin is simply a function that receives the store instance:const myPlugin = store => { store.subscribe((mutation, state) => { console.log(`mutation fired: ${mutation.type}`) console.log(`with payload:`, mutation.payload) }) }
New
Actions & Getters in the Store
You can now define actions directly inside the store and trigger them with store.dispatch(type, payload)
:
const store = new Vuex.Store({
state: { count: 0 },
mutations: {
inc: state => state.count++
},
actions: {
incAsync: ({ commit }, delay) => {
setTimeout(() => commit('inc'), delay)
}
}
})
store.dispatch('incAsync', 1000) // increment after 1 second
Same for getters, except you access getters via store.getters[name]
:
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
hasAny: state => state.count > 0
}
})
// access the getter
store.getters.hasAny // -> false
Composable Action Flow
-
To indicate the completion of an action, return a Promise from the action.
store.dispatch
will return that Promise if there is only a single handler called. If multiple action handlers are matched, it will return a Promise that resolves when all Promises returned by those handlers are resolved.const store = new Vuex.Store({ actions: { doSomething: ({ commit }, payload) => { return callPromiseAPI(payload).then(res => { commit('some-mutation', { res }) }) } } }) store.dispatch('doSomething', { id: 1 }).then(() => { // action done })
-
Based on (1) and
async/await
, we can have very clean composition between async actions:const store = new Vuex.Store({ actions: { one: async ({ commit }, payload) => { const res = await callPromiseAPI(payload) commit('some-mutation', { res }) }, two: async ({ dispatch, commit }) => { await dispatch('one') commit('done') } } }) store.dispatch('two') // fires off complicated async flow
The convention of returning Promises also allows Vuex to:
- better handle errors during async action flow.
- simplify store initialization during server-side rendering.
Component Binding Helpers
In Vuex 2.0, the vuex
option will be deprecated in favor of just computed properties and methods. You are free to structure your Vuex store usage the way you prefer. However, we will be keeping the injection for this.$store
so that you can do this:
export default {
computed: {
a () {
return this.$store.getters.a
}
},
methods: {
b (...args) {
this.$store.dispatch('b', …args)
}
}
}
The above alleviates the need to import the store everywhere. But it can get verbose when you have many getters and actions in the same component. Therefore we provide two helpers, mapGetters
and mapActions
:
import { mapGetters, mapActions } from 'vuex'
export default {
computed: mapGetters(['a', 'b', 'c']),
methods: mapActions(['d', 'e', 'f'])
}
So in the component, this.a
maps to this.$store.getters.a
, and this.d(...args)
maps to this.$store.dispatch('d', ...args)
.
If you want to map a getter/action to a different local name, use an object instead:
import { mapGetters, mapActions } from 'vuex'
export default {
computed: mapGetters({
myComputed: 'a' // map this.myComputed to store.getters.a
}),
methods: mapActions({
myMethod: 'b' // map this.myMethod() to store.dispatch('b')
})
}
Finally, you can easily compose them with local computed properties and methods using Object spread operator:
import { mapGetters, mapActions } from 'vuex'
export default {
computed: {
localComputed () { … },
...mapGetters(['a', 'b', 'c', 'd'])
},
methods: {
localMethod () { … },
...mapActions(['b'])
}
}
Nested Modules Improvements
Actions, getters and mutations are all supported inside modules.
Similar to how a module mutation receives the sub-state-tree of that module, actions and getters defined in a module will receive the sub-state-tree as well. This makes modules portable without having to be aware of the path it is nested under.
Note that module actions, getters and mutations do all share the same registration namespace with other modules, so if you want to ensure your module is well-isolated, you should consider prefixing its mutation/action types and getter names.
New API methods
-
store.module(path, moduleOptions)
Register a module into the store. The
path
argument can be either a string, or an Array of strings. When registering a nested module, its direct parent state tree must already be present. -
store.subscribe((mutation, state) => { ... })
Subscribe to state changes. Callback is called after each mutation. Typically used in plugins.