Mutation 是 Vuex 中更改状态的唯一方式。每个 mutation 都有一个字符串类型和一个回调函数,回调函数接收 state 作为参数。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
this.$store.commit('increment')
mutations: {
increment(state, amount) {
state.count += amount
}
}
this.$store.commit('increment', 10)
mutations: {
updateUserInfo(state, payload) {
state.user.name = payload.name
state.user.email = payload.email
}
}
this.$store.commit('updateUserInfo', {
name: '张三',
email: 'zhangsan@example.com'
})
this.$store.commit({
type: 'increment',
amount: 10
})
mutations: {
increment(state, payload) {
state.count += payload.amount
}
}
使用常量替代 mutation 类型名,便于维护:
export const MUTATION_TYPES = {
SET_USER: 'SET_USER',
SET_TOKEN: 'SET_TOKEN',
CLEAR_USER: 'CLEAR_USER'
}
import { MUTATION_TYPES } from './mutation-types'
const store = new Vuex.Store({
mutations: {
[MUTATION_TYPES.SET_USER](state, user) {
state.user = user
},
[MUTATION_TYPES.SET_TOKEN](state, token) {
state.token = token
},
[MUTATION_TYPES.CLEAR_USER](state) {
state.user = null
state.token = null
}
}
})
this.$store.commit(MUTATION_TYPES.SET_USER, user)
import { mapMutations } from 'vuex'
export default {
methods: {
...mapMutations(['increment', 'decrement']),
...mapMutations({
add: 'increment',
subtract: 'decrement'
})
}
}
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<button @click="add(10)">+10</button>
Mutation 必须是同步函数
mutations: {
increment(state) {
setTimeout(() => {
state.count++
}, 1000)
}
}
这会导致无法追踪状态变化,调试工具无法正确记录。
异步操作应该放在 Action 中。
mutations: {
SET_USER(state, user) {
state.user = user
state.isLoggedIn = !!user
},
SET_TOKEN(state, token) {
state.token = token
if (token) {
localStorage.setItem('token', token)
} else {
localStorage.removeItem('token')
}
},
CLEAR_USER(state) {
state.user = null
state.token = null
state.isLoggedIn = false
localStorage.removeItem('token')
},
UPDATE_USER_PROFILE(state, profile) {
state.user = { ...state.user, ...profile }
}
}
mutations: {
ADD_TO_CART(state, product) {
const existingItem = state.cart.items.find(item => item.id === product.id)
if (existingItem) {
existingItem.quantity++
} else {
state.cart.items.push({
...product,
quantity: 1
})
}
state.cart.total += product.price
state.cart.count++
},
REMOVE_FROM_CART(state, productId) {
const index = state.cart.items.findIndex(item => item.id === productId)
if (index > -1) {
const item = state.cart.items[index]
state.cart.total -= item.price * item.quantity
state.cart.count -= item.quantity
state.cart.items.splice(index, 1)
}
},
UPDATE_QUANTITY(state, { productId, quantity }) {
const item = state.cart.items.find(item => item.id === productId)
if (item) {
const diff = quantity - item.quantity
item.quantity = quantity
state.cart.total += item.price * diff
state.cart.count += diff
}
},
CLEAR_CART(state) {
state.cart.items = []
state.cart.total = 0
state.cart.count = 0
}
}
mutations: {
SET_ITEMS(state, items) {
state.items = items
},
ADD_ITEM(state, item) {
state.items.push(item)
},
UPDATE_ITEM(state, { id, data }) {
const index = state.items.findIndex(item => item.id === id)
if (index > -1) {
state.items.splice(index, 1, { ...state.items[index], ...data })
}
},
DELETE_ITEM(state, id) {
const index = state.items.findIndex(item => item.id === id)
if (index > -1) {
state.items.splice(index, 1)
}
},
SET_PAGE(state, page) {
state.pagination.page = page
}
}
mutations: {
SET_FORM_DATA(state, { field, value }) {
state.form[field] = value
},
SET_FORM_ERRORS(state, errors) {
state.formErrors = errors
},
CLEAR_FORM_ERRORS(state) {
state.formErrors = {}
},
RESET_FORM(state) {
state.form = { ...state.initialForm }
state.formErrors = {}
}
}
mutations: {
SET_LOADING(state, { key, value }) {
state.loading[key] = value
},
SET_MODAL(state, { name, visible }) {
state.modals[name] = visible
},
SET_THEME(state, theme) {
state.theme = theme
document.documentElement.setAttribute('data-theme', theme)
},
TOGGLE_SIDEBAR(state) {
state.sidebarCollapsed = !state.sidebarCollapsed
}
}
每个 mutation 只做一件事:
mutations: {
SET_USER(state, user) {
state.user = user
},
SET_TOKEN(state, token) {
state.token = token
}
}
使用大写蛇形命名:
SET_USER
UPDATE_CART
DELETE_ITEM
CLEAR_FORM
Mutation 应该简单直接:
mutations: {
SET_USER(state, user) {
state.user = user
}
}
复杂逻辑放在 Action 中:
actions: {
async login({ commit }, credentials) {
const response = await api.login(credentials)
commit('SET_USER', response.user)
commit('SET_TOKEN', response.token)
}
}
Mutation 要点: