重温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:分隔模块

 

  

 

posted @ 2022-01-26 12:00  前端乔  阅读(27)  评论(0编辑  收藏  举报