组合Action #

Action 组合方式 #

顺序执行 #

一个 Action 完成后再执行另一个:

javascript
actions: {
  async actionA({ commit }) {
    const data = await api.fetchA()
    commit('SET_A', data)
    return data
  },
  
  async actionB({ commit, dispatch }) {
    // 等待 actionA 完成
    const dataA = await dispatch('actionA')
    
    // 使用 actionA 的结果
    const dataB = await api.fetchB(dataA.id)
    commit('SET_B', dataB)
    
    return { dataA, dataB }
  }
}

并行执行 #

多个 Action 同时执行:

javascript
actions: {
  async fetchAll({ dispatch }) {
    // 并行执行
    const [users, products, orders] = await Promise.all([
      dispatch('fetchUsers'),
      dispatch('fetchProducts'),
      dispatch('fetchOrders')
    ])
    
    return { users, products, orders }
  },
  
  async fetchUsers({ commit }) {
    const users = await api.fetchUsers()
    commit('SET_USERS', users)
    return users
  },
  
  async fetchProducts({ commit }) {
    const products = await api.fetchProducts()
    commit('SET_PRODUCTS', products)
    return products
  },
  
  async fetchOrders({ commit }) {
    const orders = await api.fetchOrders()
    commit('SET_ORDERS', orders)
    return orders
  }
}

实际应用场景 #

用户登录流程 #

javascript
actions: {
  async login({ dispatch }, credentials) {
    // 1. 登录
    const { user, token } = await api.login(credentials)
    
    // 2. 保存 token
    await dispatch('saveToken', token)
    
    // 3. 获取用户详细信息
    await dispatch('fetchUserProfile', user.id)
    
    // 4. 获取用户权限
    await dispatch('fetchPermissions', user.id)
    
    // 5. 获取用户通知
    dispatch('fetchNotifications', user.id)  // 不等待
    
    return user
  },
  
  saveToken({ commit }, token) {
    localStorage.setItem('token', token)
    commit('SET_TOKEN', token)
  },
  
  async fetchUserProfile({ commit }, userId) {
    const profile = await api.getUserProfile(userId)
    commit('SET_PROFILE', profile)
    return profile
  },
  
  async fetchPermissions({ commit }, userId) {
    const permissions = await api.getUserPermissions(userId)
    commit('SET_PERMISSIONS', permissions)
    return permissions
  },
  
  async fetchNotifications({ commit }, userId) {
    const notifications = await api.getNotifications(userId)
    commit('SET_NOTIFICATIONS', notifications)
    return notifications
  }
}

购物车结算流程 #

javascript
actions: {
  async checkout({ dispatch, state, commit }) {
    commit('SET_CHECKOUT_STATUS', 'pending')
    
    try {
      // 1. 验证购物车
      await dispatch('validateCart')
      
      // 2. 验证库存
      await dispatch('validateInventory')
      
      // 3. 应用优惠
      const discount = await dispatch('applyCoupon', state.couponCode)
      
      // 4. 创建订单
      const order = await dispatch('createOrder', {
        items: state.items,
        discount
      })
      
      // 5. 处理支付
      await dispatch('processPayment', order)
      
      // 6. 清空购物车
      await dispatch('clearCart')
      
      commit('SET_CHECKOUT_STATUS', 'success')
      return order
    } catch (error) {
      commit('SET_CHECKOUT_STATUS', 'failed')
      commit('SET_ERROR', error.message)
      throw error
    }
  },
  
  async validateCart({ state }) {
    if (state.items.length === 0) {
      throw new Error('购物车为空')
    }
  },
  
  async validateInventory({ state }) {
    for (const item of state.items) {
      const inventory = await api.getInventory(item.productId)
      if (inventory < item.quantity) {
        throw new Error(`${item.name} 库存不足`)
      }
    }
  },
  
  async applyCoupon({ commit }, code) {
    if (!code) return 0
    
    const coupon = await api.validateCoupon(code)
    commit('SET_COUPON', coupon)
    return coupon.discount
  },
  
  async createOrder({ commit }, { items, discount }) {
    const order = await api.createOrder({
      items,
      discount,
      total: items.reduce((sum, item) => sum + item.price * item.quantity, 0) - discount
    })
    commit('SET_ORDER', order)
    return order
  },
  
  async processPayment({ commit }, order) {
    const payment = await api.processPayment(order)
    commit('SET_PAYMENT', payment)
    return payment
  },
  
  clearCart({ commit }) {
    commit('CLEAR_CART')
    commit('CLEAR_COUPON')
  }
}

数据初始化 #

javascript
actions: {
  async initApp({ dispatch, commit }) {
    commit('SET_APP_READY', false)
    
    try {
      // 并行获取基础数据
      await Promise.all([
        dispatch('fetchCategories'),
        dispatch('fetchSettings'),
        dispatch('fetchTranslations')
      ])
      
      // 检查登录状态
      const isLoggedIn = await dispatch('checkAuth')
      
      if (isLoggedIn) {
        // 登录后获取用户数据
        await Promise.all([
          dispatch('fetchUserProfile'),
          dispatch('fetchUserPreferences'),
          dispatch('fetchNotifications')
        ])
      }
      
      commit('SET_APP_READY', true)
    } catch (error) {
      commit('SET_INIT_ERROR', error.message)
      throw error
    }
  }
}

跨模块调用 #

调用其他模块的 Action #

javascript
// store/modules/user.js
actions: {
  async login({ dispatch }, credentials) {
    const user = await api.login(credentials)
    
    // 调用 cart 模块的 action
    await dispatch('cart/fetchCart', null, { root: true })
    
    // 调用 notifications 模块的 action
    await dispatch('notifications/fetchAll', null, { root: true })
    
    return user
  }
}

使用 rootState 和 rootGetters #

javascript
// store/modules/orders.js
actions: {
  async createOrder({ commit, rootState, rootGetters }, orderData) {
    // 访问其他模块的状态
    const user = rootState.user.current
    
    // 访问其他模块的 getter
    const discount = rootGetters['user/memberDiscount']
    
    const order = await api.createOrder({
      ...orderData,
      userId: user.id,
      discount
    })
    
    commit('ADD_ORDER', order)
    return order
  }
}

高级模式 #

条件执行 #

javascript
actions: {
  async fetchData({ state, dispatch, commit }) {
    // 如果已有数据且未过期,直接返回
    if (state.data && !isExpired(state.lastFetch)) {
      return state.data
    }
    
    // 否则重新获取
    return dispatch('refreshData')
  },
  
  async refreshData({ commit }) {
    commit('SET_LOADING', true)
    
    try {
      const data = await api.fetchData()
      commit('SET_DATA', data)
      commit('SET_LAST_FETCH', Date.now())
      return data
    } finally {
      commit('SET_LOADING', false)
    }
  }
}

队列执行 #

javascript
const actionQueue = []
let isProcessing = false

actions: {
  async queuedAction({ dispatch }, action) {
    return new Promise((resolve, reject) => {
      actionQueue.push({
        action,
        resolve,
        reject
      })
      
      if (!isProcessing) {
        dispatch('processQueue')
      }
    })
  },
  
  async processQueue({ dispatch }) {
    if (actionQueue.length === 0) {
      isProcessing = false
      return
    }
    
    isProcessing = true
    const { action, resolve, reject } = actionQueue.shift()
    
    try {
      const result = await dispatch(action.type, action.payload)
      resolve(result)
    } catch (error) {
      reject(error)
    }
    
    // 处理下一个
    await dispatch('processQueue')
  }
}

事务模式 #

javascript
actions: {
  async transferPoints({ commit, dispatch }, { fromUserId, toUserId, points }) {
    const backup = {}
    
    try {
      // 备份当前状态
      backup.fromUser = await dispatch('getUser', fromUserId)
      backup.toUser = await dispatch('getUser', toUserId)
      
      // 执行转账
      await dispatch('deductPoints', { userId: fromUserId, points })
      await dispatch('addPoints', { userId: toUserId, points })
      
      // 记录交易
      await dispatch('recordTransaction', { fromUserId, toUserId, points })
      
    } catch (error) {
      // 回滚
      commit('SET_USER', backup.fromUser)
      commit('SET_USER', backup.toUser)
      throw error
    }
  }
}

最佳实践 #

1. 保持 Action 简洁 #

javascript
// 推荐:拆分为多个小 action
actions: {
  async checkout({ dispatch }) {
    await dispatch('validateCart')
    await dispatch('processPayment')
    await dispatch('clearCart')
  }
}

// 不推荐:一个 action 做太多事
actions: {
  async checkout({ commit, state }) {
    // 所有逻辑都在这里...
  }
}

2. 合理使用并行和顺序 #

javascript
// 可以并行的操作
await Promise.all([
  dispatch('fetchUsers'),
  dispatch('fetchProducts')
])

// 有依赖的操作
const user = await dispatch('fetchUser', userId)
await dispatch('fetchUserPosts', user.id)

3. 错误处理 #

javascript
actions: {
  async complexOperation({ dispatch, commit }) {
    commit('SET_LOADING', true)
    
    try {
      const result = await dispatch('step1')
      await dispatch('step2', result)
      await dispatch('step3')
      
      commit('SET_SUCCESS', true)
    } catch (error) {
      commit('SET_ERROR', error.message)
      throw error
    } finally {
      commit('SET_LOADING', false)
    }
  }
}

总结 #

Action 组合要点:

模式 说明
顺序执行 await dispatch 依次执行
并行执行 Promise.all 同时执行
跨模块 使用
条件执行 根据状态决定是否执行

继续学习 mapActions辅助函数,简化 Action 映射。

最后更新:2026-03-28