Vuex,一个专为 Vue.js 应用程序开发的状态管理模式,用来处理在 vue 各个组件之间传值的痛苦。比如:在父子、兄弟组件,传值可能会很方便,但是如果是没有关联的组件之间要使用同一组数据,就显得及其蛋疼。而 vuex 就很好的解决了这种问题。
目录
第一步:在要使用mutations里的方法的页面引入 mapMutations
第二步:在页面中通过【this.方法名】来调用Mutations里的方法
第一步:在要使用Actions里的方法的页面引入 mapActions
第二步:在页面中通过【this.方法名】来调用Actions里的方法
同样,getters也有自己的辅助函数mapGetters 辅助函数
关于如何安装vuex,这里不做赘述,请参考官方文档
State | Vuex (vuejs.org)https://vuex.vuejs.org/zh/guide/state.html
安装好后,会在目录下生成一个store文件夹
index.js文件中的内容,就是基础的引用内容
import Vue from 'vue'
import Vuex from 'vuex'
// 注册vuex ==>将状态从根组件“注入”到每一个子组件中
Vue.use(Vuex)
// 初始化
export default new Vuex.Store({
// 申明全局使用的数据 相当于vue实例选项中的data
state: {
userName: 'cj'
},
// 存放修改state数据的方法
mutations: {},
actions: {},
modules: {}
})
通过在根实例中注册
store
选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过this.$store
访问到了,此时,state中存了一个字段,那么在其他页面中,就可以通过:this.$store.state.userName 来获取到这个值 ===> cj
Mutation 更改state状态的唯一方法
1.声明mutations方法
在子页面中,想要修改vuex中的全局字段,就需要通过mutations对象,通过调用里面定义的方法,来修改state中的数据
// mutations是更改store中state状态的唯一方法(通过store.commit调用)
// 由mutations中的方法导致的状态变更都应该在此刻完成==>也就是里面的方法必须都是同步函数,不能有异步的函数。
mutations: {
changeName (state, newName) {
// 修改state中数据
state.userName = newName
}
},
2.在页面中通过commit来调用mutations方法
在mutations对象中定义了一个changeName的方法,通过传入的参数state、newName,来对state中的数据进行修改。
在子页面中,需要通过特定的方法来调用并触发mutations里的方法:
this.$store.commit('changeName','cj2')
这样,就将state中的userName变成了 cj2
你可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload),这里就是newName
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读,参考官网的写法格式:
如果载荷是个对象的情况下,你也可以用这种写法,来调用mutations方法
this.$store.commit({
type: 'changeName',
newName: 'cj2'
})
3.mapMutations
辅助函数
当我们在页面中要使用mutations里的方法时,你当然可以每次使用都乖乖地写好下面的格式来调用方法:
this.$store.commit('方法名','载荷')
但是这样太麻烦了,所以可以使用mapMutations辅助函数,来简化页面中调用mutations里的方法
第一步:在要使用mutations里的方法的页面引入 mapMutations
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
// 将 `this.changeName()` 映射为 `this.$store.commit('changeName')`
'changeName',
'delName',
...
]),
}
}
如上,首先通过import引入这个辅助函数,然后,在页面的methods方法里通过扩展运算符,展开mapMutations辅助函数里的这个 字符串数组 里面的字符串就是mutations里的方法名。
第二步:在页面中通过【this.方法名】来调用Mutations里的方法
//通过辅助函数申明的方法,也是可以正常传入载荷(参数)的
this.changeName('cj2')
...
this.delName()
这样,就完成了对store中的state里的字段的修改了。
注意点:
由mutations中的方法导致的状态变更都应该在此刻完成 ==> 也就是里面的方法必须都是同步函数,不能有异步的函数 【例如:不能通过请求、settimeout延时后,再进行修改state】
Action 异步操作Mutations方法
action是用来异步操作mutations方法的,它提交的是mutations方法,而不是直接修改state中的数据,所以能够进行异步操作。
所谓能进行异步操作,就是调用action方法的时候,可以再里面使用异步请求,获取到数据后,在进行state的修改或其他操作,不用像mutations方法一样,一调用直接同步修改state中的内容。
1.定义好actions对象中的方法
方法可以跟mutations中的同名,也可以在末尾加上个Async表示异步
// mutations是更改store中state状态的唯一方法【通过this.$store.commit('方法名')调用】
// mutations中的方法,导致的状态变更都应该在此刻完成==>也就是里面的方法必须都是同步函数,不能有异步的函数。
mutations: {
changeName= (state, newName) => {
// 修改state中数据
state.userName = newName
}
},
...
/**
* actions可以异步操作Mutation方法。
* action 提交的是 mutation方法,而不是直接变更状态
* 【通过this.$store.dispatch('方法名','载荷')】
*/
actions: {
// 你也可以命名成 changeNameAsync,直观看出是异步的方法
changeName = ({ commit })=> {
// 异步方法返回的数据(能异步获取到数据,再去进行修改),作为载荷传给mutations方法
this.$axios.get('url', { key: 'xxx' }).then(res => {
//! 触发对应的Mutation方法,而不是直接修改state里的变量
commit('changeName', res)
})
...
setTimeout(() => {
//! 触发对应的Mutation方法,而不是直接修改state里的变量
commit('delName')
}, 1000)
}
},
2.页面中通过dispatch调用action方法
此时,在其他页面,就可以通过下方的代码(dispatch),来调用action里的异步方法了
this.$store.dispatch('changeName', 'cj2')
3.mapActions
辅助函数
同上,在页面中频繁的使用this.$store.dispatch,不美观也不方便,所以可以通过辅助函数,来批量地引入并映射方法名称,这样就能在页面里通过 【this.方法名】 来使用方法了
第一步:在要使用Actions
里的方法的页面引入 mapActions
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
// 将 `this.changeName()` 映射为 `this.$store.dispatch('changeName')`
'changeName',
'delName',
...
]),
}
}
...mapActions({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` })
为引用的方法设置别名也是可以的
第二步:在页面中通过【this.方法名】来调用Actions里的方法
//通过辅助函数申明的方法,也是可以正常传入载荷(参数)的
this.changeName('cj2')
...
this.delName()
这样,就完成了对store中的state里的字段的修改了
注意:
store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise,并且store.dispatch
仍旧返回 Promise
上面这段话什么意思呢,就是说,actions里的方法,返回的是promise类型的结果,所以,在调用actions的方法的时候,可以直接跟上.then(res=>{}),来解决回调地狱的问题
this.changeName('cj2').then(res=>{
this.delName()
})
Getter 类似于计算属性
getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
以官网的例子做演示:
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)
}
}
})
所以你能在页面中通过使用下方的形式,来调用这个方法
this.$store.getters.doneTodos
就能拿到过滤后的数据: [{ id: 1, text: '...', done: true }]
同样,getters也有自己的辅助函数mapGetters
辅助函数
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
特别地:
mapGetters辅助函数,需要在computerd 计算属性 中展开,
而其他几个辅助函数,则是需要在methods中展开
【因为getters是当作计算属性来用,而mutations、actions是当作methods来用】
这样,就能在页面中,像使用普通计算属性一样,来使用引入的方法了