vue项目中请求的loading状态管理

使用场景

项目中发起请求,难免会需要用到loading,如果我们直接使用拦截器拦截请求的发起以及响应,会导致整个项目中所有的请求公用一个状态。
如果我们需要控制每一个请求的loading状态那就非常完美了

先看效果

在这里插入图片描述

初设

为解决这个问题,我们可以使用vuex,在所有的action中设置与当前action同名的loading状态,如下

// 此函数用于模拟ajax请求,返回一个promise,将会在2s后成功
import { axiosTwo } from '@/utils/http'
import { createStore } from 'vuex'

export default createStore({
  state: {
    // 存储当前模块中所有的loading
    loading: {}
  },
  mutations: {
    // 保存loading状态到状态(state)中
    setLoading (state, { name, isLoading }) {
      state.loading[name] = isLoading
    }
  },
  actions: {
    async getList (context) {
      // 设置loading状态为true
      context.commit('setLoading', {
        name: 'getList',
        isLoading: true
      })
      await axiosTwo()
      console.log('请求完成')
      // 设置loading状态
      context.commit('setLoading', {
        name: 'getList',
        isLoading: false
      })
    }
  }
})

但是这样的话我们每个action都要重复的写上这块代码,非常不友好,容易累死,所以我们可以做一个工厂函数,让每一个经过我这里的action都变成这个样子就完美了

plus版

// 用于生成带有loading的actions
function createActions (actions) {
    // 用于记录装修过的actions
  const newActions = {}
  // 循环所有的action
  for (const fnName in actions) {
    if (Object.hasOwnProperty.call(actions, fnName)) {
      const action = actions[fnName]
    //   存储新的action
      newActions[fnName] = async function (context, payload) {
        // 在这个新的action中设置loading状态
        context.commit('setLoading', {
          name: fnName,
          isLoading: true
        })
        // 调用原本的action函数,并记录该action执行的结果
        const data = await action(context, payload)
        // 设置loading状态为false
        context.commit('setLoading', {
          name: fnName,
          isLoading: false
        })
        // 返回action的执行结果,这个如果不处理的话会导致原本action返回的数据丢失
        return data
      }
    }
  }
  return newActions
}

// 配置vuex
export default createStore({
    // state、mutations和上面相同
    actions: createActions({
        async getList () {
            await axiosTwo()
            console.log('请求完成')
        }
    })
})

最终版本

这种写法貌似也不错,但是还需要手动配置setLoading以及state,这对于不喜欢看文档的童鞋有些许的不友好,因此我们可以将这个函数进行究极进化,不需要手动配置这两个配置项

// 用于生成带有loading的action以及其他的配置
function createVuexConfig (config) {
    // 解构对应的属性,并赋默认值
    const { actions = {}, state = {}, mutations = {} } = config
    // 合并并修改state
    config.state = Object.assign(state, { loading: {} })
    // 合并并修改mutation
    config.mutations = Object.assign(mutations, {
        setLoading (state, { name, isLoading }) {
            // 保存loading状态到状态(state)中
            state.loading[name] = isLoading
        }
    })
    // 用于记录装修过的actions
    const newActions = {}
    // 循环所有的action
    for (const fnName in actions) {
        if (Object.hasOwnProperty.call(actions, fnName)) {
            const action = actions[fnName]
            // 存储新的action
            newActions[fnName] = async function (context, payload) {
                // 在这个新的action中设置loading状态
                context.commit('setLoading', {
                    name: fnName,
                    isLoading: true
                })
                // 调用原本的action函数,并记录该action执行的结果
                const data = await action(context, payload)
                // 设置loading状态为false
                context.commit('setLoading', {
                    name: fnName,
                    isLoading: false
                })
                // 返回action的执行结果,这个如果不处理的话会导致原本action返回的数据丢失
                return data
            }
        }
    }
    // 修改actions
    config.actions = newActions
    // 返回配置项
    return config
}

使用教程

仅需在配置vuex时使用该函数包裹即可

export default createStore(createVuexConfig({
  actions: {
    async getList () {
      await axiosTwo()
      console.log('请求完成')
      return '我是dispatch的执行结果'
    },
    async getTwoList () {
      await axiosTwo()
      await axiosTwo()
      console.log('两次请求完成')
    }
  }
}))

说明

本文原创,转载请注明出处

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值