Vuex中mutations和actions的区别及说明
目录
- mutation
- Mutation 必须是同步函数
- Action
- 在实际开发的store文件中
- 总结
mutation
我们知道,在使用vuex对项目状态进行管理时,只能使用commit来提交mutation对store中的状态进行更改
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (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 (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>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
赞 (0)