Action基础 #

什么是 Action? #

Action 类似于 Mutation,不同在于:

  • Action 提交的是 Mutation,而不是直接变更状态
  • Action 可以包含任意异步操作

定义 Action #

基本语法 #

javascript
const store = createStore({
  state: {
    count: 0
  },
  
  mutations: {
    INCREMENT(state) {
      state.count++
    }
  },
  
  actions: {
    // Action 函数接收 context 对象
    increment(context) {
      context.commit('INCREMENT')
    }
  }
})

使用解构 #

javascript
actions: {
  // 解构 context 对象
  increment({ commit }) {
    commit('INCREMENT')
  },
  
  // 解构更多属性
  decrement({ commit, state, getters }) {
    if (getters.canDecrement) {
      commit('DECREMENT')
    }
  }
}

context 对象 #

context 对象包含以下属性:

javascript
actions: {
  example(context) {
    // context.state    - 当前状态
    // context.rootState - 根状态
    // context.getters   - 当前 getters
    // context.rootGetters - 根 getters
    // context.commit    - 提交 mutation
    // context.dispatch  - 分发 action
  }
}

分发 Action #

普通分发 #

javascript
// 在组件中
this.$store.dispatch('increment')

// 带 payload
this.$store.dispatch('setCount', 10)

对象风格分发 #

javascript
this.$store.dispatch({
  type: 'setCount',
  value: 10
})

在 Action 中分发 #

javascript
actions: {
  actionA({ commit }) {
    commit('SET_DATA')
  },
  
  actionB({ dispatch }) {
    dispatch('actionA')  // 分发其他 action
  }
}

Action vs Mutation #

特性 Mutation Action
直接修改状态
异步操作 不允许 允许
调用方式 commit dispatch
返回值 Promise
调试 时间旅行 记录调用

异步操作 #

基本异步 #

javascript
actions: {
  async fetchUser({ commit }, userId) {
    const response = await fetch(`/api/users/${userId}`)
    const user = await response.json()
    commit('SET_USER', user)
  }
}

完整示例 #

javascript
const store = createStore({
  state: {
    user: null,
    loading: false,
    error: null
  },
  
  mutations: {
    SET_USER(state, user) {
      state.user = user
    },
    SET_LOADING(state, loading) {
      state.loading = loading
    },
    SET_ERROR(state, error) {
      state.error = error
    }
  },
  
  actions: {
    async fetchUser({ commit }, userId) {
      commit('SET_LOADING', true)
      commit('SET_ERROR', null)
      
      try {
        const response = await fetch(`/api/users/${userId}`)
        if (!response.ok) throw new Error('Failed to fetch user')
        const user = await response.json()
        commit('SET_USER', user)
      } catch (error) {
        commit('SET_ERROR', error.message)
      } finally {
        commit('SET_LOADING', false)
      }
    }
  }
})

返回 Promise #

Action 默认返回 Promise:

javascript
actions: {
  async fetchUser({ commit }, userId) {
    const user = await api.fetchUser(userId)
    commit('SET_USER', user)
    return user
  }
}

// 使用
this.$store.dispatch('fetchUser', 1)
  .then(user => {
    console.log('User:', user)
  })
  .catch(error => {
    console.error('Error:', error)
  })

// 或 async/await
async loadUser() {
  try {
    const user = await this.$store.dispatch('fetchUser', 1)
    console.log('User:', user)
  } catch (error) {
    console.error('Error:', error)
  }
}

使用 mapActions #

数组语法 #

javascript
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions([
      'fetchUser',
      'login',
      'logout'
    ])
  }
}

// 使用
this.fetchUser(1)
this.login({ username, password })

对象语法 #

javascript
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions({
      loadUser: 'fetchUser',
      signIn: 'login',
      signOut: 'logout'
    })
  }
}

组合式 API 中使用 #

vue
<script>
import { useStore } from 'vuex'

export default {
  setup() {
    const store = useStore()
    
    const fetchUser = async (userId) => {
      return await store.dispatch('fetchUser', userId)
    }
    
    return {
      fetchUser
    }
  }
}
</script>

实战示例 #

用户认证 #

javascript
// store/modules/auth.js
export default {
  namespaced: true,
  
  state: {
    user: null,
    token: null,
    loading: false,
    error: null
  },
  
  mutations: {
    SET_USER(state, user) {
      state.user = user
    },
    SET_TOKEN(state, token) {
      state.token = token
    },
    SET_LOADING(state, loading) {
      state.loading = loading
    },
    SET_ERROR(state, error) {
      state.error = error
    },
    CLEAR_AUTH(state) {
      state.user = null
      state.token = null
    }
  },
  
  actions: {
    async login({ commit }, credentials) {
      commit('SET_LOADING', true)
      commit('SET_ERROR', null)
      
      try {
        const response = await api.login(credentials)
        commit('SET_USER', response.user)
        commit('SET_TOKEN', response.token)
        localStorage.setItem('token', response.token)
        return response.user
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    async logout({ commit }) {
      await api.logout()
      localStorage.removeItem('token')
      commit('CLEAR_AUTH')
    },
    
    async checkAuth({ commit }) {
      const token = localStorage.getItem('token')
      if (!token) return false
      
      try {
        const user = await api.getCurrentUser()
        commit('SET_USER', user)
        commit('SET_TOKEN', token)
        return true
      } catch {
        commit('CLEAR_AUTH')
        return false
      }
    }
  }
}

数据获取 #

javascript
// store/modules/products.js
export default {
  namespaced: true,
  
  state: {
    items: [],
    current: null,
    loading: false,
    error: null
  },
  
  mutations: {
    SET_ITEMS(state, items) {
      state.items = items
    },
    SET_CURRENT(state, item) {
      state.current = item
    },
    ADD_ITEM(state, item) {
      state.items.push(item)
    },
    UPDATE_ITEM(state, updatedItem) {
      const index = state.items.findIndex(i => i.id === updatedItem.id)
      if (index !== -1) {
        state.items[index] = updatedItem
      }
    },
    REMOVE_ITEM(state, id) {
      state.items = state.items.filter(i => i.id !== id)
    },
    SET_LOADING(state, loading) {
      state.loading = loading
    },
    SET_ERROR(state, error) {
      state.error = error
    }
  },
  
  actions: {
    async fetchAll({ commit }, filters = {}) {
      commit('SET_LOADING', true)
      commit('SET_ERROR', null)
      
      try {
        const items = await api.getProducts(filters)
        commit('SET_ITEMS', items)
        return items
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    async fetchOne({ commit }, id) {
      commit('SET_LOADING', true)
      
      try {
        const item = await api.getProduct(id)
        commit('SET_CURRENT', item)
        return item
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    async create({ commit }, data) {
      commit('SET_LOADING', true)
      
      try {
        const item = await api.createProduct(data)
        commit('ADD_ITEM', item)
        return item
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    async update({ commit }, { id, data }) {
      commit('SET_LOADING', true)
      
      try {
        const item = await api.updateProduct(id, data)
        commit('UPDATE_ITEM', item)
        return item
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    async remove({ commit }, id) {
      commit('SET_LOADING', true)
      
      try {
        await api.deleteProduct(id)
        commit('REMOVE_ITEM', id)
      } catch (error) {
        commit('SET_ERROR', error.message)
        throw error
      } finally {
        commit('SET_LOADING', false)
      }
    }
  }
}

总结 #

Action 核心要点:

要点 说明
异步处理 Action 用于处理异步操作
提交 Mutation 通过 commit 修改状态
返回 Promise Action 返回 Promise
分发方式 通过 dispatch 调用

继续学习 异步操作,深入了解异步处理技巧。

最后更新:2026-03-28