不少刚学Vuex的同学都会疑惑,mutations和actions看起来都能搞事情,但到底哪里不一样?今天就把这俩的区别掰碎了讲,从职责、用法到实际开发场景,一次性讲清楚~
修改状态的“规则” vs 业务逻辑的“载体”
Vuex的设计里,state
是存储数据的“仓库”,而mutations
和actions
是控制数据变化的“开关”,但分工完全不同:
-
mutations:状态修改的“唯一合法通道”
它是Vuex里唯一允许直接修改state的地方,有点像银行柜台——只有它能合法“动”账户里的钱,比如state里存了个count
,想让count
加1,就得在mutations里写个increment
函数,专门负责改这个值,而且mutation必须是同步操作,因为要让Vuex的调试工具(devtools)能精准追踪每一次状态变化,调试时能回退、能看变化记录。 -
actions:业务逻辑的“协调者”
它不直接碰state,而是触发mutation来间接改状态,actions主打处理异步操作(比如调接口、用定时器),还能整合多个mutation或其他action,相当于“业务流程管家”,举个例子:用户登录时,action要先调后端接口拿token(这是异步),拿到后再通过commit mutation把token存到state里,这里action负责“登录流程”这个完整业务,mutation只负责单纯的状态修改。
使用场景:什么时候用mutation,什么时候用action?
用生活场景类比更直观:
-
该用mutation的场景:纯状态修改,没异步、没复杂逻辑。
点击按钮让数字加1”“切换主题颜色”“修改用户昵称”——这些操作“直给”,不需要等、不需要和外部交互,直接改状态就行,代码里就是定义一个mutation类型(比如SET_NICKNAME
),接收新昵称当参数,然后commit这个mutation。 -
该用action的场景:有异步、有多步骤、要和外部交互(比如调API、操作本地存储)。
加载用户信息”:action里得先调接口getUserInfo()
,拿到数据后,再commit多个mutation(比如SET_USERNAME
改用户名、SET_AVATAR
改头像);再比如“购物车结算”:action里要检查库存(调接口)、生成订单(调接口)、修改购物车状态(commit mutation),这些步骤得串起来,action就负责统筹。
简单总结:只要涉及“等一下再改状态”(异步)或者“改状态前要做很多事”(复杂逻辑),就用action;单纯“现在改状态”,用mutation。
语法与调用方式:直接触发 vs 异步触发
从代码怎么写、怎么调,也能看出两者区别:
-
mutation的写法与调用
在store的mutations
里定义函数,第一个参数是state
(要改的状态对象),第二个是payload
(传递的数据),触发时用this.$store.commit('mutation名称', 数据)
。mutations: { SET_COUNT(state, newCount) { state.count = newCount; // 直接改state } } // 组件里触发: this.$store.commit('SET_COUNT', 10);
注意!mutation里绝对不能写异步代码(比如
setTimeout
或axios
请求),否则devtools追踪不到状态变化,调试时会乱套。 -
action的写法与调用
在store的actions
里定义函数,第一个参数是context
(包含commit
、dispatch
、state
等方法),也可以解构用{ commit }
,触发时用this.$store.dispatch('action名称', 数据)
,而且action里能自由写异步,actions: { async fetchUserInfo({ commit }) { const res = await axios.get('/user'); // 异步请求 commit('SET_USER', res.data); // 用mutation改状态 } } // 组件里触发: this.$store.dispatch('fetchUserInfo');
action还能返回Promise,方便外部用
.then()
或await
处理,比如登录成功后跳转页面:actions: { login({ commit }, userInfo) { return axios.post('/login', userInfo) .then(res => { commit('SET_TOKEN', res.data.token); return res.data; // 把数据返回给调用处 }); } } // 组件里用: this.$store.dispatch('login', { username, password }) .then(() => { this.$router.push('/home'); // 登录成功跳转 });
严格模式下的约束差异
Vuex有个严格模式(配置strict: true
),打开后对状态修改的约束更严格,这时候mutation和action的区别会被放大:
-
mutation在严格模式下:只有通过它修改state才合法,如果在组件里直接写
this.$store.state.count = 10
,控制台会报错,这强制要求“状态修改必须走mutation”,保证每一次状态变化都能被追踪。 -
action在严格模式下:本身不能直接修改state,必须通过
commit mutation
来改,如果action里写state.count = 10
,同样会报错,这也符合设计逻辑:action是“指挥”,负责统筹逻辑;mutation是“执行者”,负责单纯改状态,职责必须分开。
举个错误案例:如果在action里直接改state,严格模式下会报错:
actions: { badAction({ state }) { state.count = 10; // 严格模式下报错!action不能直接改state } }
正确做法是在action里commit mutation:
actions: { goodAction({ commit }) { commit('SET_COUNT', 10); // 正确,通过mutation改state } }
实际开发中的协作:mutation和action怎么配合?
理解区别后,还要知道怎么在项目里配合着用,比如做一个“点赞”功能,流程应该是这样:
- 组件触发action:用户点击“点赞”按钮时,调用
this.$store.dispatch('likeArticle', articleId)
。 - action处理异步与逻辑:在action里调接口记录点赞(异步),成功后触发mutation改状态:
actions: { async likeArticle({ commit }, articleId) { const res = await axios.post(`/article/${articleId}/like`); if (res.data.success) { commit('INCREMENT_LIKE', articleId); // 调用mutation改状态 } } }
- mutation修改state:在mutation里找到对应文章,更新点赞数:
mutations: { INCREMENT_LIKE(state, articleId) { const article = state.articles.find(a => a.id === articleId); article.likeCount++; } }
这里action负责“和后端交互 + 决定是否修改状态”,mutation负责“单纯的状态更新”,分工明确后,代码维护性更高:如果以后要加点赞动画、埋点,都能塞到action里;如果要改状态更新逻辑(比如同时改点赞数和用户积分),只需要改mutation或者新增mutation,action不用动。
记住这张“区别表”
最后整理个对比表,方便快速记忆:
维度 | mutations | actions |
---|---|---|
核心职责 | 直接修改state(唯一合法入口) | 处理异步/复杂逻辑,提交mutation |
操作类型 | 同步操作(必须) | 异步、同步都支持 |
触发方式 | this.$store.commit() |
this.$store.dispatch() |
直接改state? | 可以(且只有这里能合法改) | 不可以(必须通过commit mutation) |
严格模式约束 | 仅允许通过它修改state | 不能直接改state,需走mutation |
刚学Vuex时,mutation和action像“双胞胎”,但实际职责、用法、约束完全不同,mutation管同步改状态,action管异步和逻辑协调”,写代码时先想清楚操作性质,选对工具,逻辑自然更清晰~ 下次开发遇到状态管理,别再把这俩搞混啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。