Vuex是专门为vue.js开发的状态管理模式(状态就是数据),采用集中式存贮管理应用的状态;相当于把组件中的数据提升到一个全局的地方(所有的组件都能访问到),则就是vuex的store,当需要某一个组件的数据时,直接从store中获取(this.$store.state.数据名);

  1. Vuex的状态存储是响应式的,当vue组件从store中读取状态时,如果store的状态发生变化,相应组件也会相应更新
  2. 改变store中的状态的唯一途径是显式提交mutation

主要模块

  • State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
  • Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
  • Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
  • Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
  • Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

Vuex使用步骤

  1. 按照vuex,并且配置store.js文件
    2. 把需要vuex托管的数据放到state中
    3. 如果state中的数据需要被修改,则创建相应的mutation
    4. 如果state中的数据会被异步修改,则创建相应的action,并且在action中使用commit mutation的方式修改state里面的数据
    5. 最后导出一个Vuex的Store实例,并且在创建Vue的根实例的时候配置,配置store属性以后,在组件中可以通过this.$store访问store实例
    6. 在整个Vue的应用中,任何地方都能访问状态,通过this.$store.state.数据名的方式
    7. 更新数据,如果是同步更新,提交mutation【this.$store.commit(mutation的名字,传给mutation的参数)】;如果是异步更新,分发action【this.$store.dispatch(action的名字,payload)】
    `

    Vuex基本使用

  2. 获取公共状态信息:this.$store.state.xxx

  3. 直接调取mutation中的方法:this.$store.commit([mutation-function-name],[payload])
  4. 调取acttion中的方法:this.$store.dispatch([actions-function-name],[payload])
  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3. //Vuex是vue中的插件
  4. Vue.use(Vuex);
  5. /*vuex 中的数据是存在内存中的,一刷新就没有了*/
  6. //创建store容器(管理数据)并且导出
  7. //存储到store中的状态是响应式的,当store中的状态发生变更时,所有用到的状态的地方都自动更新
  8. export default new Vuex.Store({
  9. //state存贮公共状态(data)
  10. state:{
  11. b:12
  12. },
  13. //mutations存储sync function,这些方法改变state中的状态信息
  14. //mutations的方法只能通过commit mutation的方法调用
  15. mutations:{
  16. example1(state){
  17. //state就是上面的state对象,通过state可以修改state里面的状态
  18. state.num++
  19. },
  20. example(state,payload){
  21. //state容器中存储的状态信息
  22. //payload是commit执行的时候传递进来的参数信息,通常是一个对象
  23. //this.$store.commit('example',1000)
  24. console.log(payload)
  25. state.num+=payload.num
  26. }
  27. },
  28. //actions存储async存储async function,这些方法首先异步获取需要的数据,然后在基于commit触发mutations中的方法,从而改变state
  29. actions:{
  30. //在actions下面的方法称为action,action中可以有异步程序,例如ajax和定时器,
  31. //在action中更新状态,仍需要提交到mutation
  32. asyncadd(context,payload){
  33. //context对象上有commit方法,commit()方法可以提交mutation
  34. //context 对象上还有dispatch方法,用来分发其他的action
  35. //this.$store.dispatch('exampleAction','aa')
  36. //
  37. setTimeout(_=>{
  38. context.commit('example',1000);
  39. // context.commit('example1',1000);
  40. },1000)
  41. }
  42. },
  43. //getters储存的方式等价于computed计算属性,监听当前容器中的state的计算属性
  44. getters:{
  45. //add(state){}
  46. }
  47. });
  48. //如果修改store中的数据,只要提交mutation;但是mutation函数中只能同步的程序的(修改state里面的状态不能写在异步程序中)
  49. //异步处理在哪里:写在actions中
  50. //如果这些数据被多处依赖了,再放到vuex中,
  51. //vuex在项目中的应用,很多人都喜欢把数据都写在vuex中,不管是不是被多处依赖了

基于各种map简化操作方式

1. 基本语法

  1. import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
  2. export default {
  3. computed:{
  4. //=>数组方式
  5. ...mapState(['n','m']), //=>this.n
  6. //=>对象方式
  7. ...mapState({
  8. a:'n', //=>this.a === this.$store.state.n
  9. }),
  10. //=>函数方式
  11. ...mapState({
  12. a:state=>state.xxx.xxx
  13. })
  14. },
  15. //=>其余的map操作方式和mapState类似
  16. }


module按照模块进行分组

  1. store.js
  1. import Vue from 'vue';
  2. import Vuex from 'vuex';
  3. import logger from 'vuex/dist/logger';
  4. import Person from './Person';
  5. import Product from './Product';
  6. Vue.use(Vuex);
  7. export default new Vuex.store({
  8. //把每一个模块中的state-actions都进行合并
  9. //1. state会按照各版块进行区分, state={Person:{...},Product:{...},isLogin:true}
  10. //2. getters/mutations/actions默认不会进行模块划分,默认全部合并在一起,会导致冲突,
  11. //解决方案:每一个模块设置namespaced:true,这样在最后合并在一起的时候,会以模块的名字作为前缀,进行标识区分
  12. // mutations={'Person/changeName':function xxx,
  13. // 'Product/changeName':function xxx,
  14. // changeLogin:function xxx,...
  15. // }
  16. modules:{
  17. Person,
  18. Product
  19. },
  20. //各个板块公共的状态和方法
  21. state:{
  22. isLogin:true
  23. },
  24. getters:{
  25. queryLogin(state){return state.isLogin;}
  26. },
  27. mutations:{
  28. changeLogin(state,payload){
  29. changeLogin(state,payload){
  30. state.isLogin=payload;
  31. }
  32. }
  33. },
  34. plugins: [logger()]
  35. })

person.js

  1. /*
  2. * 个人中心板块中的公共状态管理
  3. */
  4. export default{
  5. namespaced:true,
  6. state:{
  7. name:'珠峰',
  8. baseInfo:{
  9. email:'121312232@qq.com',
  10. phone:'1223232323'
  11. }
  12. },
  13. getters:{
  14. queryBase(state){
  15. //=>state:本模块的私有状态
  16. // console.log(state);
  17. return `${state.name}的邮箱是:${state.baseInfo.email}`;
  18. }
  19. },
  20. mutations:{
  21. changeName(state,payload){
  22. state.name=payload;
  23. },
  24. changeBase(state,payload){
  25. state.baseInfo={
  26. ...state.baseInfo,
  27. ...payload
  28. };
  29. }
  30. },
  31. actions:{
  32. actionDemo(context,payload){
  33. // context.state 当前模块私有的状态
  34. // context.rootState 整个store中的全部状态
  35. // console.log(context, payload);
  36. }
  37. }

product.js

  1. /*
  2. * 产品板块中的公共状态管理
  3. */
  4. import * as types from './store-type';
  5. export default{
  6. namespaced:true,
  7. state:{
  8. name:'就业',
  9. baseInfo:{
  10. time:'5 m'
  11. }
  12. },
  13. getters:{
  14. [types.PRODUCT_GETTER_QUERY_BASE](state){
  15. return ``${state.name}课程的周期是:${state.baseInfo.time}`;
  16. }
  17. },
  18. mutations:{
  19. [types.PRODUCT_MUTATION_CHANGE_NAME](state, payload) {
  20. state.name = payload;
  21. }
  22. }
  23. }

store-types.js

  1. //宏标识名称管理
  2. export const PRODUCT_MUTATION_CHANGE_NAME="PRODUCT_MUTATION_CHANGE_NAME";
  3. export const PRODUCT_GETTER_QUERY_BASE="PRODUCT_GETTER_QUERY_BASE"

获取状态或者触发mutations/actions中的方法执行

  1. this.$store.state.Product.js
  2. this.$store.dispatch(‘Product.js/xxx’)
  3. …mapActions(‘Product.js’,[‘xxx’])
  4. 基于createNamespacedHelpers处理
  1. import {createNamespacedHelpers} from 'vuex'
  2. let {mapActions,mapState}=createNamespacedHelpers('product.js')
  3. ...mapActions(['xxx']);

Vuex中的面试题

Vuex和单纯的全局对象有什么区别?

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  • 不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。

    为什么 Vuex 的 mutation 中不能做异步操作?

  • Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现

  • 每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

    Vuex的action有返回值吗?返回的是什么?

  • store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise

  • Action 通常是异步的,要知道 action 什么时候结束或者组合多个 action以处理更加复杂的异步流程,可以通过定义action时返回一个promise对象,在派发action的时候就可以通过处理返回的 Promise处理异步流程

一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。

为什么不直接分发mutation,而要通过分发action之后提交 mutation变更状态

  • mutation 必须同步执行,我们可以在 action 内部执行异步操作
  • 可以进行一系列的异步操作,并且通过提交 mutation 来记录 action 产生的副作用(即状态变更)