Vuex中mutations和actions的区别及说明

2022-12-09 10:09:11

目录mutationMutation必须是同步函数Action在实际开发的store文件中总结mutation我们知道,在使用vuex对项目状态进行管理时,只能使用commit来提交mutation...

目录
mutation
Mutation 必须是同步函数
Action
在实际开发的store文件中
总结

mutation

我们知道,在使用vuex对项目状态进行管理时,只能使用commit来提交mutation对store中的状态进行更改

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个php 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

const store = new Vuex.Store({
 state: {
  count: 1
 },
 mutations: {
  increment (state) {
   // 变更状态
   state.count++
  }
 }
})
//你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:
store.commit('increment') 

Mutation 必须是同步函数

mutations: {
 someMutation (state) {
  api.callAsyncMethod(() => {
   state.count++
  })
 }
}

我们注意上面这段代码,在mutation里面加入了异步处理的函数。

其实mutation是可以正常使用的,但是我们在日常的开发中debug的时候,我们需要查看devtool中的mutation日志。

理论上来说,是mutation走一步,devtool记录一步,但是在mutation中加入异步函数就会导致我们devtool的记录失败,因为devtool不知道你里面的异步函数什么时候调用,在哪里调用

Action

Action 类似于 mutation,不同在于:

Action 提交的是 mutation,而不是直接变更状态。

Action 可以包含任意异步操作。

const store = new Vuex.Store({
 state: {
  count: 0
 },
 mutations: {
  increment (state) {
   state.count++
  }
 },
 actions: {
  increment (context) {
   context.commit('increment')
  }
 }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

实践中,我们会经常用到 ES2015 的 参数解构 (opens new window)来简化代码(特别是我们需要调用 commit 很多次的时候):

actions: {
 increment ({ commit }) {
  commit('increment')
 }
}

在实际开发的store文件中

// src/store/index.js

import Vue from 'vue';
import Vuex from '@/vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
 state: {
  num: 10
 },
 getters: {
  getPrice(state) {
   return state.num * 10
  }
 },
 // 同步更新状态
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'

const user = {
 state: {
  token: getToken(),
  name: '',
  avatar: '',
  roles: [],
  permissions: []
 },
//同步方法
 mutations: {
  SET_TOKEN: (state, token) => {
   state.token = token
  },
  SET_NAME: (state, name) => {
   state.name = name
  },
  SET_AVATAR: (state, avatar) => {
   state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
   state.roles = roles
  },
  SET_PERMISSIONS: (state, permissions) => {
   state.permissions = permissions
  }
 },
//异步方法
 actions: {
  // 登录(使用单点登录此处就作废)
  Login({ commit }, userInfo) {
   const loginType = userInfo.loginType
   const tentantCode = userInfo.tentantCode
   const username = userInfo.username.trim()
   const password = userInfo.password
   const code = userInfo.code
   const uuid = userInfo.uuid
   return new Promise((resolve, reject) => {
    login(loginType, 编程tentantCode, username, password, code, uuid).then(res => {
     setToken(res.token)
     commit('SET_TOKEN', res.token)
     resolve()
    }).catch(error => {
     reject(error)
    })
   })
  },

  // 获取用户信息
  GetInfo({ commit, state }) {
   return new Promise((resolve, reject) => {
    getInfo().then(res => {
     if (res.data.rolePermission
      && res.data.rolePermission
      > 0) { // 验证返回的roles是否是一个非空数组
      commit('SET_ROLES', res.roles)
      commit('SET_PERMISSIONS', res.permissions)
     } else {
      commit('SET_ROLES', ['ROLE_DEFAULT'])
     }
     commit('SET_NAME', res.data.nickName
     )
     commit('SET_AVATAR', res.data.avatar)
     resolve(res)
    }).catch(error => {
     reject(error)
    })
   })
  },

  // 退出系统
  LogOut({ commit, state }) {
   return new Promise((resolve, reject) => {
    logout(state.token).then(() => {
     commit('SET_TOKEN', '')
     commit('SET_ROLES', [])
     commit('SET_PERMISSIONS', [])
     removeToken()
     resolve()
    }).catch(error => {
     reject(error)
    })
   })
  },

  // 前端 登出
  FedLogOut({ commit }) {
   return new Promise(resolve => {
    commit('SET_TOKEN', '')
    removeToken()
    resolve()
   })
  }
 }
}

export default user

比如我们在登录的时候需要触发store中的方法

<template>
 <div>单点登录页面</div>
</template>

<script>
import {
 doLoginByTicket,
 getInfo,
 isLogin,
 getSsoAuthUrl,
 getRouter,
} from "../api/login";
import { getToken, setToken } from "@/utils/auth";
export default {
 name: "Screenfull",
 data() {
  return {};
 },
 created() {
  this.checkIsLogin();
 },

 methods: {
  checkIsLogin() {
   isLogin().then((res) => {
    if (res.data == true) {
     //获取用户信息;
     console.log("isLogin", res);
     // this.$router.push("/");
    } else {
     //获取请求进来的完整url
     let url = window.location.href;
     if XHKYOPzHg(url.indexOf("ticket=") < 0) {
      //如果没有ticket
      getSsoAuthUrl({ clientLoginUrl: url }).then((res) => {
       window.location.href = res.data;
      });
      return;
     }
     let tstr = url
      .substring(url.indexOf("?") + 1)
      .split("=")[1]
      .split("#")[0]; //先截取url的?后面的参数部分,在根据&分割成参数数组
     doLoginByTicket({ ticket: tstr }).then((res) => {
      if (res.code == 200) {
       setToken(res.data);
       getInfo().then((res) => {
        if (res.data.rolePermission) {
        //触发mutations同步方法
         this.$store.commit("SET_ROLES", ["admin"]);
         this.$store.commit("SET_PERMISSIONS", ["*:*:*"]);
        } else {
         commit("SET_ROLES", ["ROLE_DEFAULT"]);
        }
        this.$store.commit("SET_NAME", res.data.nickName);
       });
       getRouter().then(() => {
    //触发actions异步方法
        this.$store.dispatch("GenerateRoutes");
        window.location.reload();
       });
      } else {
       console.log("检查票据失败");
      }
     });
    }
   });
  },
 },
};
</script>

<style lang="scss" scoped></style>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。