重温vuex
一、Vuex是什么?
vuex是一个专为vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex也集中到vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能
什么是“状态管理模式”?
这个状态自管理应用包含一下几个部分:
- state,驱动应用数据源
- view,以声明方式将state映射到视图;
- actions,响应在view上的用户输入导致状态的变化
什么情况下我应该使用vuex?
vuex可以帮助我们管理共享状态,并附带了更多的概念和框架,这需要对短期和长期效益进行权衡。如果您不打算开发大型单页面应用,使用vuex可能是繁琐的。但是如果你需要构建一个中大型单页应用,你很可能会考虑如何更好的在组件外部管理状态,vuex将会成为自然而然的选择。
二、核心概念
state
- 存储在 Vuex 中的数据
- 在vue组件中获得vuex状态:store.state.count、this.$store.state.count、...mapState(['count'])
getters
- 有时候我们需要从store中派生出一些状态,例如对列表进行过滤并计数:
/* vuex允许我们在store中定义“getteer”(课可以认为是store的计算属性)。就像计算属性 */ const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } })
通过属性访问
getter会暴漏为store.getters队形,你可以以计算属性的形式访问这些值:
store.getters.doneTodos
getter也可以接受其他getter作为第二个参数
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
我们可以和容易的在人和组件中使用它:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } } //通过方法访问 getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) //注意,getter在通过方法访问时,每次都会去进行调用,而不会缓存结果
//通过mapGetters辅助函数
import {mapGetters} from 'vuex'
export default{
computed:{
...mapGetters([
'doneTodosCount'
])
}
}
Mutation
更改vuex的store中的状态的唯一方法是mutation。vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且会接受state作为第一个参数:
const store=new vuex.Store({ state:{ count:1 }, mutations:{ increment(state){ state.count++ } } })
你不能直接调用mutation中的handler。这个选项更像是事件注册:“当触发一个类型为increment”的mutation时,调用此函数。“要唤醒一个mutation handler”,你需要以相应的type调用store.commit方法:
store.commit('increment')
提交载荷(payload)
你可以向store.commit传入额外的参数,即mutation的载荷
mutations: { increment (state, n) { state.count += n } } store.commit('increment', 10) //在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读: mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 })
注意:mutation需遵循vue响应规则,mutation必须是同步函数
Action
在mutation中混合异步调用会导致你的程序很难调用。例如,当你调用了两个包含异步回调的mutation来改变状态,你怎么知道什么时候回调和那个先回调?这就是为什吗我们要区别这两个概念。在vuex中,mutation都是同步事务:
action类似于mutation,不同于:
- action提交的是mutation,而不是直接变更状态。
- Action可以包含任意异步操作。
让我们来注册一个简单的action:
const store=new Vuex.Store({ state:{ count:0 }, mutation:{ increment(state){ state.count++ } }, actions:{ increment(context){ context.commit('increnment') } } })
//利用es6的参数解构
actions:{
increment({commit}){
commit('increment')
}
}
Action函数接受一个store实例具有相同方法和属性的context对象,因为你可以调用conext.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。
分发Action
action通过store.dispatch方法触发:
store.dispatch('increment')
乍一看感觉多此一举,我们直接分发mutation岂不是更方便吗?实际上并非如此,还记得mutation必须同步执行这个限制吗?action就不受约束!我们可以在action内部执行异步操作:
在组件中分发Action,你可以使用this.$store.dispatch('XXX')分发action,或者使用mapActions辅助函数将组件的methods映射为store.dispatch调用()
import {mapActions} from 'vuex' export default { ...mapAction(['increment','incremenBy']), ...mapActions({add:"increment"}) }
组合Action
action通常是异步的,那么如何知道action什么时候结束呢?更重要的是,我们如何才能组合多个action,已处理更复杂的异步流程?首先,你需要明白,store.dispath可以处理被触发的action的处理函数返回的promise,并且store.dispatch仍旧返回promise:
1 actions:{ 2 actionA({commit}){ 3 returen new Promise(resolve,reject)=>{ 4 setTimeout(()=>{ 5 commit('someMutation') 6 resolve() 7 },1000) 8 } 9 10 } 11 } 12 //现在你可以: 13 store.dispatch('actionA').then(()=>{}) 14 //在另外一个action中也可以: 15 action:{ 16 actionB({dispatch,commit}){ 17 return dispatch('actionA').then(()=>{ 18 commit (''someOtherMutation) 19 }) 20 } 21 }
最后,如果我们利用async/await,我们可以如下组合action:
actions:{ async actionA({commit}){ commit('gotData',await getData()) }, async actionB({dispatch,commit}){ await dispatch('actionA') commit(‘gotOtherData’, await getOherData()) } }
Modules:分隔模块