在进行复杂一点的项目开发时,咱们会发现只是普通的组件间的数据传递已经不足以知足咱们的需求,因此咱们须要引入Vue中管理状态工具--Vuex
// 若是在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) store.commit('increment')// 经过commit去触发mutations中的increment方法 console.log(store.state.count) // -> 1
在Vuex中使用state保存了所有的应用层级的状态,咱们能够经过store.state.[变量名]去获取状态值,在一般的状况下,咱们能够直接在每一个须要使用state的组件中引入store,可是这种方式会频繁地在各个组件中导入,会影响性能;因此通常的解决方法是先在根实例中注册store,该实例会注册到子组件中,这样的话,在子组件中咱们就能够经过this.$store.state.[变量名]去获取到想要的状态。vue
// 第一种方式:在使用到state的组件中引入store const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { // 经过计算属性去返回状态 return store.state.count } } } // 第二种方式:在根组件的实例中,把 store 对象提供给 “store” 选项 const app = new Vue({ el: '#app', store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` }) const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count // 在子组件中只须要使用this.$store就可使用 } } }
前面说state的使用方法时,咱们说到能够经过计算属性的去拿到想要获取的状态,可是若是咱们要在同一个组件中获取多个状态时,咱们就能够利用mapState了,下面是它的用法:vuex
// 在store实例的state中存放值 state: { name: '', age: '', sex: '' } // 在子组件的计算属性中去获取store中存放的值 compute: { ...mapState(['name']) }
getter主要是用来存放由state派生出的一些状态,若是不少组件都须要使用到这个状态,就须要在每一个组件中根据state计算再计算一遍,这样就容易形成代码的冗余。store中提供了一个getter属性,能够专门用来存放store中的state衍生出来的状态,以下面的用法:数组
// state中存放的是todos属性 const store = new Vuex.Store({ state: { todos: [ { id: 1, done: true }, { id: 2, done: false } ] }, getters: {// getters中存放的是由state派生出来,会屡次用到的值 doneTodos: state => {// 第一个参数是state return state.todos.filter(todo => todo.done) } } })
能够经过store.getters去获取Getter对象,而后经过访问属性的方式去获取getters中的内容,好比下例:promise
store.getters.doneTodos // -> [{ id: 1, done: true }]
getters也能够将本身做为参数使用,在方法中直接获取getters中的内容:缓存
getters: { // 获取doneTodos的长度 doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
能够经过在getter中返回一个函数来给getter传参,这个比较适用于查找store中的数组,好比下面的用法:app
getters: { // 经过给getTodoById传入id来获取对应的项 getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) // -> { id: 2, done: false }
使用属性的方式去访问有缓存,经过方法去访问的话,每次都会被调用一次,不会有缓存。异步
mapGetters和mapStates是同样的做用,都是为了便于在子组件中获取多个状态,用法也相似,这里就很少说明了。async
在Vuex中,mutations的角色就至关因而vue中的methods,它能够用来存放方法,mutations中的类型名就至关因而methods中的方法名,每一个mutation中的会有一个回调函数,可是在methods中能够没有返回值。模块化
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变动状态 state.count++ } } }) // 经过commit去使用mutations中的方法,这也是改变state中的状态的惟一方法 store.commit('increment')
在commit的时候也能够传入额外的参数,即mutation的载荷(payload),一般这个参数会传入一个对象,以下面的用法:函数
mutations: { increment (state, payload) { state.count += payload.amount } } // 在commit的时候给他传递一个对象,这样的好处是更加易懂明了 store.commit('increment', { amount: 10 }) // 还可使用对象的方式去提交 store.commit({ type: 'increment', amount: 10 })
在一个大型项目中,Mutations中的事件可能会比较多,这时将每种类型都用一个常量去表示,而后将这些常量放在一个静态文件中,打开静态文件,就能够一目了然地看到Mutations中有哪些事件,好比下面的用法:
// mutation-types.js // 在存放类型名的文件中将该类型常量抛出来 export const SOME_MUTATION = 'SOME_MUTATION' // store.js // 在store中引入该常量 import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { [SOME_MUTATION] (state) { // ... } } })
以前咱们说到过若是想要改变state,惟一的方法就是使用commit去改变,这样作是由于咱们想要更明确地跟踪state状态的变化。若是mutation是异步函数的话,就不知道state具体是什么时间发送变化的,这就和以前设计的初衷相悖了。还有可能有多个异步mutation时,使用commit去改变的话就分辨不出来是哪一个先进行回调,因此这也是比较麻烦的事。
为了解决异步回调的问题,Vuex中定义了一个相似于mutation的action,action是专门处理异步问题的,它接受一个和store变量具备相同属性和方法的对象--context,因此能够用该对象去调用commit进行提交。
action和mutation有如下两点区别:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, // 在actions中去调用mutations中的方法 actions: { increment (context) { context.commit('increment') } } })
以前说过在action中能够提交mutations,可是它不只仅是用来提交同步函数的,还能够在其中执行异步操做,以下用法:
// 在actions中执行异步操做 actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }
// 能够经过store.dispatch去触发action store.dispatch('incrementAsync') // 和commit相似,dispatch也可使用对象的方式载荷发布 store.dispatch('incrementAsync', { amount: 10 }) store.dispatch({ type: 'incrementAsync', amount: 10 })
在组件中分发action的方式有两种:
// 使用this.$store.dispatch分发 this.$store.dispatch('incrementAsync') // 使用mapActions将组件中的方法映射为store.dispatch调用 import { mapActions } from 'vuex' export default { methods: { ...mapActions([ // 将this.increment()映射成this.$store.dispatch('increment') 'increment', // 将this.increment(amount)映射成this.$store.dispatch('increment', amount) 'incrementBy' ]), ...mapActions([ // 将this.add()映射成this.$store.dispatch('increment') add: 'increment' ]) } }
使用dispatch返回的是promise对象,而且在dispatch中也能够处理promise对象,用法以下:
actions: { // actionA返回的是一个promise对象 actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }
store.dispatch('actionA')
actions: { actionB ({ commit, dispatch }) { return dispatch('actionA').then(() => { commit('someMutation') }) } }
// 假设 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } }
基本内容就是这么多了,项目中目前使用到的就是这些,这篇文章只是对Vuex经常使用内容的一个总结,更多的东西能够去看Vuex官网,若是有什么错误欢迎指出哦~