vuex全面用法总结详解

一、vuex的简介

Vuex是一个专为Vue开发的应用程序的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

简而言之:Vuex采用类似全局对象的形式来管理所有组件的公用数据,如果想修改这个全局对象的数据名得按照Vuex提供的方式来修改(不能自己随意用自己的方式来修改),核心就是store(仓库),仓库是用来干什么的?你就当它是用来存储东西的。

二、vuex的优点是什么?

Vuexx状态管理使用传统全局变量的不同之处:

1.Vuex的状态存储是响应式:就是当你的组件使用到了在这个Vuex的状态,一旦它改变了,所有关联的组件都会自动更新相对应的数据,这样开发者省事很多。

2.不能直接修改Vuex的状态:如果是个全局对象变量,要修改很容易,但是在Vuex中不能这样做,想修改就得使用Vuex提供得唯一途径:显示地提交(commit)mutations来实现修改。这样做的好处就是方便我们跟踪每一个状态得变化,在开发过程中调试的时候,就非常使用啦

vuex的结构示意图如下:

在这里插入图片描述

三、我们什么时候应该用到Vuex呢?

1、小应用不建议使用Vuex,因为小项目使用Vuex可能会比较繁琐冗余;
2、中大型单页应用,因为要考虑如何更好地在组件外部管理状态,Vuex将会成为自然而然地选择

四、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,需要先记住两点:

  • 1、store中存储的状态是为响应的,当组件从store中读取状态时,如果store中的状态发生了改变,那么响应的组件也会得到更新。
  • 2、不能直接改变store中的改变。改变store中的状态的唯一途径是提交(commit)mutations.这样使我们方便跟踪到每一个状态。

五、一个完整的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

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的使用

当一个组件去获取多种的状态时,则在计算属性中要去写多个函数,这里为了方便,可以使用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计算属性全部混合在一起了.

八、getters的使用

有很多时候我们需要从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

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>

十.actions

因为mutations中只能是同步操作,但是在实际的项目中,会有异步操作,那么action中提交mutation,然后在组件的methods中去提交action。只是提交actions的时候使用的是dispatch函数,而mutations则是用commit函数。

十.一 一个简单的action

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是一样的,不再赘述

十.二 在组件中分发action

方法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>

十一.一 组合actions

因为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');
     })
  }
}

十一.二 mudules

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时声明的模块)。

十二、 含有vuex的项目的结构

十二.一 应该遵循的规则

  • 应用层级的状态都应该集中在store中

  • 提交 mutation 是更改状态state的唯一方式,并且这个过程是同步的。

  • 异步的操作应该都放在action里面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值