Vuex中mutations和actions的那些事儿:为啥非要分家?

大家好,我是小杨,一个被Vuex虐过千百遍的前端老司机。今天咱们来聊聊Vuex里最让人困惑的两个概念------mutations和actions。为啥非要分开?为啥不能在mutations里写异步?看完这篇你就全明白了!

1. mutations:唯一能改state的"会计"

记得我刚用Vuex时,觉得mutations这玩意儿真多余,直接改state不香吗?后来项目出bug了才明白它的重要性。

mutations的核心特点

  • 唯一能修改state的地方(财务部独享修改权限)
  • 必须是同步函数(所有修改都要记录在案)
  • 通过commit触发(要走正规流程)
javascript 复制代码
// store/modules/user.js
const mutations = {
  // ✅ 正确的mutation
  SET_USER(state, user) {
    state.user = user
  },
  
  // ❌ 错误示范(虽然能运行,但违背设计原则)
  async SET_USER_ASYNC(state, user) {
    await someAsyncOperation()
    state.user = user // 千万别这么干!
  }
}

2. actions:处理异步的"业务员"

actions就像公司的业务部门,专门处理各种外部对接:

actions的核心特点

  • 可以包含异步操作(跟API打交道)
  • 不能直接修改state(没财务权限)
  • 通过dispatch触发(业务部门的工作流程)
javascript 复制代码
const actions = {
  async login({ commit }, credentials) {
    try {
      const user = await api.login(credentials) // 异步请求
      commit('SET_USER', user) // 走正规流程修改state
      return user
    } catch (error) {
      console.error('登录失败', error)
      throw error
    }
  }
}

3. 为啥非要分开?一次惨痛的教训

去年我做了一个电商项目,当时图省事在mutation里调接口:

javascript 复制代码
// ❌ 灾难性写法
mutations: {
  async GET_PRODUCTS(state) {
    state.loading = true
    const res = await api.getProducts() // 异步请求
    state.products = res.data
    state.loading = false
  }
}

结果出现两个致命问题:

  1. DevTools无法正确追踪状态变化
  2. 多个异步mutation导致状态更新顺序错乱

4. 官方为啥这么设计?

Vuex作者的设计意图其实很明确:

特性 mutations actions
能否修改state ✅ 能 ❌ 不能
同步/异步 ❌ 必须同步 ✅ 可以异步
触发方式 commit dispatch
定位 状态变更记录 业务逻辑处理

5. 我的最佳实践

经过多年踩坑,我总结出这样的分工原则:

javascript 复制代码
// 数据获取流程示例
actions: {
  async fetchData({ commit }) {
    commit('SET_LOADING', true) // mutation改状态
    const data = await api.getData() // action处理异步
    commit('SET_DATA', data) // mutation改状态
    commit('SET_LOADING', false)
    return data
  }
},

mutations: {
  SET_LOADING(state, isLoading) {
    state.isLoading = isLoading
  },
  SET_DATA(state, data) {
    state.data = data
  }
}

6. 特殊场景处理

有时候我们确实需要在mutation之后执行一些操作,可以用subscribe:

javascript 复制代码
// 在组件中监听mutation
this.$store.subscribe((mutation, state) => {
  if (mutation.type === 'SET_USER') {
    // 用户数据更新后的操作
    localStorage.setItem('user', JSON.stringify(state.user))
  }
})

7. 常见误区答疑

Q:我就是想在mutation里写异步,会怎样?

A:就像让会计去跑业务,短期可能没问题,但迟早会账目混乱!

Q:actions能直接改state吗?

A:技术上可以(通过this._vm),但千万别这么干,会破坏Vuex的可预测性

Q:小型项目也要这么严格吗?

A:养成分离的好习惯,项目大了才不会翻车

总结

记住这个黄金法则:

  • mutations:只管同步修改state(财务)
  • actions:处理异步和业务逻辑(业务)

就像公司要有明确的部门分工,Vuex也需要清晰的职责划分。现在你明白为啥Vuex要这么设计了吧?

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
青皮桔21 分钟前
CSS实现百分比水柱图
前端·css
失落的多巴胺21 分钟前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear24 分钟前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息26 分钟前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月28 分钟前
1.vue权衡的艺术
前端·vue.js·开源
RunsenLIu29 分钟前
基于Vue.js + Node.js + MySQL实现的图书销售管理系统
vue.js·mysql·node.js
样子201832 分钟前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿32 分钟前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
翻滚吧键盘33 分钟前
vue文本插值
javascript·vue.js·ecmascript
华子w90892585934 分钟前
基于 SpringBoot+Vue.js+ElementUI 的 “花开富贵“ 花园管理系统设计与实现7000字论文
vue.js·spring boot·elementui