vue 学习笔记 - vuex

很早就听说过vuex,但是一直没用过。正好做到了登录这一块,趁着这个机会掌握它。

一. 对Vuex的理解

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 ---引用自Vuex官网

我个人的理解是这样的,就拿登录来说,登录是一种状态,在网站中有可能登录后的好多页面和未登录的状态都是不同的,把每个页面想象成组件,也就是说多个组件都要共享这个登录状态,如果是采用传参的方式来共享,会变得很繁琐,就像是多个函数嵌套一样,要一层一层的将参数传递下去,而且不易维护,这时候就需要将这种多个组件共享的状态或是数据抽取出来,单独存放在一个地方,只要需要这些状态或者数据的组件,都去这个地方找就好了,那么实现这个功能的东西就叫做Vuex。

二. Vuex中的核心概念

  • state

    state就是数据源,也就是说所有共享的数据都存放在这个地方,例子:

    使用vue-cli搭建的项目,会有一个store.js的文件

    import Vue from "vue";
    import Vuex from "vuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
        state: {
            isLogin: false  // state里面就可以放共享的数据
        },
        mutations: {},
        actions: {}
    });
    
    复制代码

    其他组件如果要获取state里面的数据,可以通过this.$store.state.xxx获得

    export default {
        name: "HelloWorld",
        props: {
            msg: String
        },
        mounted() {
            console.log(this.$store.state.isLogin)
        },
    };
    复制代码
    • mapState

      假如一个组件需要获取多个共享数据,例子:

      // store.js
      
      export default new Vuex.Store({
          state: {
              isLogin: false,
              name: "admin",
              password: 123456
          },
          mutations: {},
          actions: {}
      });
      复制代码
      // HelloWorld.vue
      
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          computed: {
              isLogin() {
                  return this.$store.state.isLogin
              },
              name() {
                  return this.$store.state.name
              },
              passsword() {
                  return this.$store.state.password
              }
          },
      };
      复制代码

      例子中是一个一个的写出来,3个还好。假如有10个写起来就很麻烦了。

      mapState可以解决这个问题:

      上面的例子用mapState写就是这样的:

      // HelloWorld.vue
      import { mapState } from 'vuex';
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          computed: mapState(['isLogin', 'name', 'password'])
      };
      复制代码

      mapState的参数如果是数组的话,那数组的每一项就是state中数据的key值,按照官网的说法是:映射 this.isLogin 为 store.state.isLogin。

      但是computed不可能只有state里的属性,还有组件自身的属性,这时候就要使用对象展开运算符了:

      // HelloWorld.vue
      import { mapState } from 'vuex';
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          computed: {
              greetings() {
                  return `${this.name}!你好`
              },
              ...mapState(['isLogin', 'name', 'password'])
          }
      };
      复制代码

      结果:

      mapState还可以传入一个对象,比如上面例子可以改写成这样

      // HelloWorld.vue
      import { mapState } from 'vuex';
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          computed: {
              ...mapState({
                  isLogin: state => state.isLogin,
                  name: state => state.isLogin,
                  password: 'password',
                  greetings(state) {
                      return `${state.name}!你好`
                  }
              })
          }
      };
      复制代码

      结果:

      这两种写法都可获得state中对应key值得数据

      isLogin: state => state.isLogin
      password: 'password'
      复制代码

      依赖state中的计算属性可以使用例子中函数的方式,

      greetings(state) {
          return `${state.name}!你好`
      }
      复制代码

      注意不要使用箭头函数,为了保证this指向正确(没看过源码,不知道调用方式,所以不能确定this的指向,但是官方文档说不要使用箭头函数,按照文档的来)

    • Getter

      官方文档上有一句话我觉得已经解释的很清楚了:

      可以认为是 store 的计算属性 ---引用自Vuex官网

      直接看例子:

      // store.js
      export default new Vuex.Store({
          state: {
              todeList: [
                  { task: "追番", isDone: false },
                  { task: "玩游戏", isDone: false },
                  { task: "睡觉", isDone: true }
              ]
          },
          mutations: {},
          actions: {}
      });
      复制代码

      现在需要获得todeList中已完成的事项数量。如果只有一个组件需要,那么直接在组件内部filter就好了,如果是多个组件都要,那又出现了重复代码的情况,这种情况下可以使用getters解决:

      // store.js
      export default new Vuex.Store({
          state: {
              todeList: [
                  { task: "追番", isDone: false },
                  { task: "玩游戏", isDone: false },
                  { task: "睡觉", isDone: true }
              ]
          },
          getters: {
              doneList: state => {
                  return state.todeList.filter(task => task.isDone);
              }
          }
          mutations: {},
          actions: {}
      });
      复制代码
      // HelloWorld.vue
      
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          computed: {
              doneAmount() {
                  return this.$store.getters.doneList.length;
              }
          }
      };
      复制代码

      每当state中的数据变化,getter中依赖它的数据就会重新计算,在各个组件中也就不用重复的去写那些方法了,直接获取即可。

      getters中的getter还有几种其他的写法:

      • getter可以引用其他getter。上面的例子可以改成这样:

        // store.js
        export default new Vuex.Store({
            state: {
                todeList: [
                    { task: "追番", isDone: false },
                    { task: "玩游戏", isDone: false },
                    { task: "睡觉", isDone: true }
                ]
            },
            getters: {
                doneList: state => {
                    return state.todeList.filter(task => task.isDone);
                },
                doneAmount: (state, getters) => {
                    return getters.doneList.length;
                }
            },
            mutations: {},
            actions: {}
        });
        复制代码
        // HelloWorld.vue
        export default {
            name: "HelloWorld",
            props: {
                msg: String
            },
            computed: {
                doneAmount() {
                    return this.$store.getters.doneAmount;
                }
            }
        };
        复制代码

        这样改完之后组件里直接用doneAmount就行了,getters中的doneAmount会根据doneList的改变而重新计算出数量。

      • getter可以返回一个函数,使用的时候就可以给getter传参数了

        // store.js
        export default new Vuex.Store({
            state: {
                todeList: [
                    { task: "追番", isDone: false },
                    { task: "玩游戏", isDone: false },
                    { task: "睡觉", isDone: true }
                ]
            },
            getters: {
                getTask: state => taskName => {
                    return state.todeList.find(taskItem => taskName === taskItem.task);
                }
            },
            mutations: {},
            actions: {}
        });
        复制代码
        // HelloWorld.vue
        export default {
            name: "HelloWorld",
            props: {
                msg: String
            },
            computed: {
                task() {
                    return this.$store.getters.getTask('玩游戏')
                }
            }
        };
        复制代码

      同样,getter也有辅助的函数mapGetters,它和mapState差不多,这里就不继续说了。

    • Mutation

      想要改变state中的数据,在vuex中唯一的办法就是提交一个mutation,直接看看它的使用方式吧,例子:

      • 不带参数

        // store.js
        export default new Vuex.Store({
            state: {
                num: 0
            },
            getters: {},
            mutations: {
                addOne(state) {
                    state.num++
                }
            },
            actions: {}
        });
        复制代码
        // HelloWorld.vue
        export default {
            name: "HelloWorld",
            props: {
                msg: String
            },
            mounted() {
                this.$store.commit('addOne')
                console.log(this.num)
            },
            computed: {
                num() {
                    return this.$store.state.num
                }
            }
        };
        复制代码
      • 带参数

        // store.js
        export default new Vuex.Store({
            state: {
                num: 0
            },
            getters: {},
            mutations: {
                add(state, n) {
                    state.num += n
                },
                multiplication(state, payload) {
                    state.num *= payload.num;
                }
            },
            actions: {}
        });
        复制代码
        // HelloWorld.vue
        export default {
            name: "HelloWorld",
            props: {
                msg: String
            },
            mounted() {
                this.$store.commit('add', 10)
                this.$store.commit('multiplication', {
                    num: 10
                })
                this.$store.commit({
                    type: 'multiplication',
                    num: 10
                })
                console.log(this.num)
            },
            computed: {
                num() {
                    return this.$store.state.num
                }
            }
        };
        复制代码

        带参数方式中如果参数是对象,有两种写法,一种是把mutation的名字作为第一个参数,第二种是第一个参数是对象,对象中有个type属性,type属性的值就是mutation的名字。

      mutation也有辅助函数mapMutations,上面例子可以写成下面这样:

      // HelloWorld.vue
      import { mapMutations } from "vuex";
      export default {
          name: "HelloWorld",
          props: {
              msg: String
          },
          mounted() {
              this.add(10)
              this.multiplication({
                  num: 100
              })
          },
          methods: {
              ...mapMutations([
                  'add',
                  'multiplication'
              ])
          },
          computed: {
              num() {
                  return this.$store.state.num
              }
          }
      };
      复制代码

      mutation还需要注意的两点有:

      • mutation事件名建议使用常量代替(官方推荐):

        // 常量也建议全部存放在单独的文件中
        const MUTATION_ADD = 'MUTATION_ADD'
        
        
        mutations: {
            [MUTATION_ADD](state, n) {
                state.num += n
            }
        }
        复制代码
      • mutation 必须是同步函数,原因参考官网

    • Action

      由于mutation只能是同步函数,如果有异步的操作,那么就可以用action。例子:

      export default new Vuex.Store({
          state: {
              num: 1
          },
          getters: {},
          mutations: {
              add(state, payload) {
                  state.num += payload.num;
              }
          },
          actions: {
              add(context, payload) {
                  setTimeout(() => {
                      context.commit("add", payload);
                  }, 1000);
              }
          }
      });
      复制代码

      action就好像吧mutation包了一层一样,在action中就可以使用各种异步了。 组件中使用action用的是这样的方式:

      this.$store.dispatch('xxx')
      this.$store.dispatch('xxx', {key: value})
      this.$store.dispatch({
          type: 'xxx',
          key: value
      })
      复制代码

      action还可以这样用:

      actions: {
          actionOne() {
              return new Promise(reslove => {
                  console.log("呆死ki");
                  reslove();
              });
          },
          add(context, payload) {
              context.dispatch("actionOne").then(() => {
                  setTimeout(() => {
                      context.commit("add", payload);
                  }, 1000);
              });
          }
      }
      复制代码

      它的辅助函数叫mapActions,用法和mapMutations类似。

    最后剩Module,目前还没用过,所以理解可能会有问题。这里就不说了。

    总结下就是:

    vuex中:

    • store:作为一个容器,里面包含了state,mutation等等,就像一个vue的实例一样。
    • state:store中的数据源。
    • getter:store中的计算属性
    • mutation:修改state的唯一方法就是提交一个mutation,mutation只能是同步函数
    • action:由于mutation只能是同步函数,那么有异步的操作就要用到action,action就好像将mutation包裹了一层一样。
    • module: 如果store特别的庞大,可以使用module将它分割成模块。

转载于:https://juejin.im/post/5c7622b7e51d453f0a16ad26

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值