赞
踩
Vuex是一个专为Vue开发的应用程序的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简而言之:Vuex采用类似全局对象的形式来管理所有组件的公用数据,如果想修改这个全局对象的数据名得按照Vuex提供的方式来修改(不能自己随意用自己的方式来修改),核心就是store(仓库),仓库是用来干什么的?你就当它是用来存储东西的。
Vuexx状态管理使用传统全局变量的不同之处:
1.Vuex的状态存储是响应式:就是当你的组件使用到了在这个Vuex的状态,一旦它改变了,所有关联的组件都会自动更新相对应的数据,这样开发者省事很多。
2.不能直接修改Vuex的状态:如果是个全局对象变量,要修改很容易,但是在Vuex中不能这样做,想修改就得使用Vuex提供得唯一途径:显示地提交(commit)mutations来实现修改。这样做的好处就是方便我们跟踪每一个状态得变化,在开发过程中调试的时候,就非常使用啦
1、小应用不建议使用Vuex,因为小项目使用Vuex可能会比较繁琐冗余;
2、中大型单页应用,因为要考虑如何更好地在组件外部管理状态,Vuex将会成为自然而然地选择
1、State: 定义了应用状态的数据结构,可以在这里设置默认的初始状态(存放状态)
2、Getter:允许组件从store中去获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性(state的计算属性)
3、Mutation:是唯一更改store中状态的方法,且必须是同步函数(更改状态的逻辑,同步操作)
4、Action:用于提交mutation,而不是直接变更状态,可以包含任意异步操作。(提交mutation,异步操作)
5、Module:可以将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter甚至是嵌套子模块。(将store模块化)
关于store,需要先记住两点:
const store = new Vuex.Store({ state:{ //存放状态 }, getters:{ //state的计算属性 }, mutations: { //更改state中状态的逻辑,同步操作 }, actions: { //提交mutation,异步操作 }, //如果将store分成一个个的模块的话,则需要用到modules. //然后在每一个module中的state,getters,mutations,actions等 modules: { a: moduleA, b: moduleB, //... } });
vuex状态是响应式的,所以从store中读取状态的方法是在组件的计算属性中返回某个状态!!!
import store from 'store';
const Counter = {
template:`<div>{{ count }}`,
computed: {
count () {
//去获取store中的状态
return store.state.count;
}
}
}
根据以上的步骤组件中的状态就与store的状态关联起来了。每当store.state.count发生改变时,都会重新求取计算属性,从而去更新DOM。
每个组件都需要反复倒入store。可以将store注入到vue实例对象中去,这样每一个组件中都需要直接去获取store中的状态,而不需要反复导入store了
const app = new Vue({
el: '#app',
//把store对象注入到vue中去了
store,
components: { Counter},
template: `<div>
<counter></counter>
<div>
`
});
上面的代码可以在组件中使用this.$store.count访问到state里面的count这个状态
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
//获取store中的状态
return this.$store.state.count;
}
}
}
当一个组件去获取多种的状态时,则在计算属性中要去写多个函数,这里为了方便,可以使用mapState辅助函数来帮我们生成计算属性
import { mapState } from 'vuex'; export default { //... data (){ localState: 1 } computed: mapState({ //此处的state即为store里面的state状态 count: state => state.count, //当计算属性的名称与state的状态名称一样时,可以进行省写 //映射this.count1为store.state.count1 count1, //'count'等同于‘state => state.count’ countAlias: 'count', countPlus (state){ //使用普通函数是为了保证this.指向组件对象 rerurn state.count + this.localState; } }) } //上面是通过mapState的对象来赋值的,还可以通过mapState的数组来赋值 computed: mapState(['count']); //这种方式很简洁,但是组件中的state的名称就跟store中映射过来的同名!
对象扩展运算符
mapState 函数返回的是一个对象,为了将它里面的计算属性与组件本身的局部计算属性组合起来,需要用到对象扩展运算符。
computed: {
localState (){
...mapState ({
})
}
}
以上的操作…mapState的计算属性就与localState计算属性全部混合在一起了.
有很多时候我们需要从store中的state中派生出一些状态,例如对列表进行过滤并计数。此时可以用到getters,getters可以看作是store的计算属性,其参数为state。
const store = new Vuex.Store({
state: {
todos: [
{id:1,text: 'reading',done: true},
{id:2,text: 'playBastKetball',done: false}
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done);
}
}
});
获取getters里面的状态,方法一:
store.getters.doneTodos //[{id:1,text: 'reding',done: true}]
//在组件中,则要写在计算属性中去
computed: {
doneTods (){
return this.$store.getters.doneTodos;
}
}
使用mapGetters获取getters里面的状态,方法二:
import {mapState,mapGetters} from 'vuex';
computed: {
...mapState({'increment'}),
...mapGetters({'doneTodos'})
}
mutations里面是如何更改state中状态的逻辑。更改Vuex中的state的唯一方法是,提交mutation,即store.commit(‘increment’).
九.一 提交载荷(payload)
可以向commit传入额外的参数,即mutation的载荷
mutations: {
increment(state, n){
state.count +=n;
}
}
store.commit('increment', 10);
payload还可以是一个对象
mutations: {
increment(state, payload)
state.count +=payload.amount;
}
}
store.commit('increment', {amount:10});
还可以使用type属性来提交mutation
store.commit({
type: 'increment',
amount: 10
});
//mutations保持不变
mutations: {
increment(state, payload)
state.count +=payload.amount;
}
注意:mutation必须是同步函数,不能是异步的,这是为了后期调试的方便。
九.二 在组件中提交mutations
mutation应该在哪里进行提交呢???因为是js是基于事件驱动的,所以改变状态的逻辑肯定是由事件来驱动的,所以store.commit(‘increment’)是在组件的methods中来执行的。
方法一:在组件的methods中进行提交。
methods: {
increment(){
this.$store.commit('increment');
}
}
方法二:使用mapMutaions
用mapMutations辅助函数将组件中的methods映射为store.commit调用。
import { mapMutations } from 'vuex';
export default {
//...
methods: {
...mapMutations([
'increment' //映射this.increment()为this.$store.commit('increment')
]),
...mapMutations([
add: 'increment' //映射this.add()改为this.$store.commit('increment')
])
}
}
//因为mutation相当于一个method,所以在组件中,可以这样来使用
<button @click="increment">+</button>
因为mutations中只能是同步操作,但是在实际的项目中,会有异步操作,那么action中提交mutation,然后在组件的methods中去提交action。只是提交actions的时候使用的是dispatch函数,而mutations则是用commit函数。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state){ state.count++; } }, actions: { increment(context){ context.commit('increment'); } /*可以用参数结构的方法来写action increment({commit}){ commit('increment'); } */ } }); //action函数接受一个context参数,这个context具有与store实例相同的方法和属性
action同样支持payload和对象方式来分发,格式跟commit是一样的,不再赘述
方法1:在组件的methods中,使用this.$store.dispatch(‘increment’)。
方法2:使用mapActions,跟mapMutations是类似的
import {mapActions} from 'vuex'
export default {
//...
methods: {
...mapActions([
'increment' //映射this.increment() 为this.$store.dispatch('increment')
]),
...mapActions({
add: 'increment' //映射this.add()为this.$store.dispatch('increment') })
}
}
//同样在组件中,可以这样来使用
<button @click="increment">+</button>
因为action是异步的,那么我们需要知道这个异步函数什么时候结束,以及等到执行后,会利用某个action的结果。这个可以使用promise来实现。在一个action中返回一个promise,然后使用then()回调函数来处理这个action返回的结果。
actions:{ actionA({commit}){ return new Promise(resolve,reject) => { setTimeout(() => { commit('someMutation'); resolve(); },1000); }) } } //这样就可以操作actionA返回的结果了 store,dispatch('actionA').then(() => { //dosomething... }); //也可以选另一个action中使用actionA的结果 actions: { //... actionB({ dispatch,commit}){ return dispatch('actionA').then(() => { commit('someOtherMutation'); }) } }
module是为了将store拆分后的一个个小模块,这么做的目的是因为当store很大的时候,分成模块的话,方便管理。
十一、三 每个module拥有自己的state, getters, mutation, action
const moduleA = { state: {...}, getters: {...}, mutations: {....}, actions: {...} } const moduleB = { state: {...}, getters: {...}, mutations: {....}, actions: {...} } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }); store.state.a // 获取moduleA的状态 store.state.b // 获取moduleB的状态
对于模块内部的mutation和getter,接受的第一个参数是模块的局部状态state。顺便说一下,根结点的状态为rootState。
const moduleA = {
state: { count: 0},
getters: {
doubleCount(state){
return state.count * 2;
}
},
mutations: {
increment(state){
state.count ++ ;
}
},
actions: {...}
}
对于模块内部的mutation和getter,接受的第一个参数是模块的局部状态state。顺便说一下,根结点的状态为rootState。
const moduleA = {
state: { count: 0},
getters: {
doubleCount(state){
return state.count * 2;
}
},
mutations: {
increment(state){
state.count ++ ;
}
},
actions: {...}
}
在模块创建之后,可以使用store.registerModule方法来注册模块。
store.registerModule('myModule', {
// ...
});
可以通过store.state.myModule来获取模块的状态。
可以使用store.unregisterModule(moduleName)来动态的卸载模块,但是这种方法对于静态模块是无效的(即在创建store时声明的模块)。
十二.一 应该遵循的规则
应用层级的状态都应该集中在store中
提交 mutation 是更改状态state的唯一方式,并且这个过程是同步的。
异步的操作应该都放在action里面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。