vue/uniapp 异步请求状态管理 加载更多,成功,加载中,失败

16 篇文章 0 订阅
13 篇文章 0 订阅

描述

之前用过react的ahook很舒服,但是vue的ahook功能太少。于是仿照react ahooks的useRequest 写的异步请求状态管理 加载更多,成功,加载中,失败

示意图

请添加图片描述

测试代码

<template>
  <view>
    <h2>自动触发</h2>
    <view v-if="state.loading">loading</view>
    <view v-else-if="state.error">error</view>
    <view v-else>{{state.data}}</view>
    <view>------------------------</view>
    <h2>手动触发</h2>
    <view v-if="manualState.loading">loading</view>
    <view v-else-if="manualState.error">error</view>
    <view v-else>{{manualState.data}}</view>
    <button @click="manualState.run()">加载数据</button>
    <view>------------------------</view>
    <h2>局部刷新</h2>
    <view v-if="hotState.loading">loading</view>
    <view v-else-if="hotState.error">error</view>
    <view v-else>
      {{hotState.data}}
      <text v-if="hotState.isRefresh">局部刷新中</text>
    </view>
    <button @click="hotState.reFresh()">局部刷新</button>
    <view>------------------------</view>
    <h2>加载更多</h2>
    <view v-if="listState.loading">loading</view>
    <view v-else-if="listState.error">error</view>
    <view v-for="item in listState.data">{{item.name}}</view>
    <view v-if="listState.loadingMore">加载中</view>
    <view v-if="!listState.isThereMore">没有更多了</view>
    <button @click="loadMore">加载更多</button>
    <view>------------------------</view>
  </view>
</template>

<script>
import {useRequest} from './useRequest'
import moment from "moment";

//模拟普通接口
function commonApi() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        code: 0,
        result: moment().format("hh:mm:ss"),
        message: 'success'
      })
    }, 1000)
  })
}
//模拟列表
function listApi(data){
  return new Promise((resolve, reject) => {
    setTimeout(()=>{
      resolve({
        code:0,
        message:"",
        result:{
          total:12,
          records:[
            {
              name:'tang'+data,id:1
            },
            {
              name:'tang',id:2
            },
            {
              name:'tang',id:3
            },
            {
              name:'tang',id:1
            },
          ]
        }
      })
    },1000)
  })
}

//模拟调用接口
async function getCommonData() {
  const e = await commonApi()
  if (e.code === 0) return e.result
  else throw e.message
}
//模拟调用接口
async function getListData(data) {
  const e = await listApi(data)
  if (e.code === 0) return e.result
  else throw e.message
}
export default {
  created() {
    //如果参数依赖其他的data,则只能在data初始化之后操作
    //pageNum没啥用 只是告诉下 带参数怎么使用
    this.listState=useRequest(()=>getListData(this.pageNum),{loadMoreMod: true})
  },
  data() {
    return {
      state: useRequest(getCommonData),
      manualState:useRequest(getCommonData,{manual:true}),
      hotState:useRequest(getCommonData),
      listState:"",
      pageNum:1,
    }
  },
  methods: {
    loadMore(){
      this.pageNum++
      this.listState.loadMore()
    },
  }
}
</script>

<style>

</style>

useRequest 代码


/**
 * 描述:异步状态管理
 * 参数1 apiFunc
 *      必须是一个Promise。
 * 参数2 option
 *      manual:是否要手动出发,默认false,初始化时候就会调用一次接口,否则则需要自己手动调用run方法
 *      onSuccess:成功时候的回调,返回获取的数据
 *      onError:失败时候的回调,返回失败信息
 *      loadMoreMod 将以 加载更多 模式运行 将所有请求数据合并数组 .then(e)成功返回的数据必须有为{total:Number,records:[]},不是的自己await时候洗一下.
 * 返回值
 *      普通模式下
 *              let state = {
                        data: null, //返回的数据
                        loading: !manual, //是否正在加载
                        error: null, //错误信息
                        isRefresh: false, //是否正在局部刷新
                        run(params) ,调用接口,params是参数,会直接传给了apiFunc(params),当然如果你的apifunc不接受参数,那就当然没用了。
                        reFresh() 局部刷新。和run的区别就是,调用的时候不会将data重新置为null,而是在加载成功后替换掉。
                   }
        加载更多模式下
                 let state = {
                        data: null, //返回的数据
                        loading: !manual, //是否正在加载
                        error: null, //错误信息
                        run(params) ,调用接口,params是参数,会直接传给了apiFunc(params),当然如果你传递apiFunc不接受参数,那就当然没用了。

                        isThereMore:是否还有更多的数据
                        loadingMore:是否正在加载更多中
                        isReloading:是否正在重新加载中,只是为了和loading状态区分开。
                        reLoad():重新加载
                        loadMore():加载更多
                   }
 */
function useRequest(apiFunc, option = {
    manual: false,
    onSuccess: false,
    onError: false,
    loadMoreMod:false,
}) {
    const {manual, onSuccess, onError,loadMoreMod} = option
    //通用状态
    let state = {
        data: null,
        loading: !manual,
        error: null,
        isRefresh: false,
    }
    //如果开启了加载更多模式则添加【是否有更多数据状态】
    if(loadMoreMod){
        state.isThereMore=true
        state.loadingMore=false
        state.isReloading=false
    }

    //保存下查询的参数,列表带参数,调用reload后传递的参数保存下,给下次loadMore时候用。
    let tempParams=""

    const execute = (params,opt={isRefresh:false,isReload:false}) => {
        const {isRefresh,isReload}=opt
        apiFunc(params)
            .then((e) => {
                state.loading = false
                //加载更多模式 合并请求的数据
                if(loadMoreMod){
                    state.loadingMore=false
                    handleLoadMoreModData(e,isReload)
                }
                //普通模式
                else {
                    state.data = e
                    if(isRefresh){
                        state.isRefresh=false
                    }
                }

                //如果是正在reload 关闭状态
                if(isReload)
                    state.isReloading=false

                if (onSuccess) {
                    onSuccess(e)
                }
            })
            .catch((e) => {
                state.error = e.toString()
                state.loading = false
                if(isRefresh){
                    state.isRefresh=false
                }
                uni.showToast({
                    title: '错误:' + e.toString(),
                    icon: "none",
                    duration: 2000
                })
                if (onError) {
                    onError(e.toString())
                }
            })
    }

    //加载更多模式下处理s tate.data 合并数据
    const handleLoadMoreModData=(e,isReload)=>{
        const {total,records}=e
        //第二次之合并数据 如果不是reload
        if(state.data&&!isReload){
            //合并数据
            state.data=[...state.data,...records]
            //判断是否还有数据
            const recordsLength=state.data.length
            /*
            * 为啥是大于等于呢,正常情况下等于是没问题的
            * 但是第一次查10条,一共十二条,第二次查询的时候,突然删的只剩下一条数据了,那么返回的total是不是1 是不是就比当前合并的数组少了。
            * */
            if(recordsLength>=total)
                state.isThereMore=false
        }
        //第一次直接赋值
        else{
            //如果有值
            if(total!==0)
                state.data=records
            else{
                state.data=[]
                state.isThereMore=false
            }

        }
    }


    //普通执行 会清空之前查询的数据 相当于reLoad 、
    const run = (params) => {
        if(loadMoreMod){
            state.loadingMore=false
            state.isThereMore=true
            state.isReloading=false
            tempParams=params//加载更多模式保存查询参数,给reload,和loadMore用
        }
        state.error = null//重置错误状态
        state.loading = true//加载状态改为加载中
        state.data = null//重置之前查询的数据
        //执行
        execute(params)
    }

    //局部刷新
    const reFresh=()=>{
        state.isRefresh = true//加载状态改为加载中
        //执行
        if(tempParams)
            execute(tempParams,{isRefresh: true})
        else
            execute(undefined,{isRefresh: true})
    }

    //加载更多
    const loadMore=()=>{
        //如果还要更多的数据,而且当前不是正在加载更多的状态
        if(state.isThereMore&&!state.loadingMore){
            state.loadingMore=true
            //执行
            //如果有保存的参数,则传递保存的参数
            if(tempParams)
                execute(tempParams)
            else
                execute()
        }
    }

    //重新加载
    const reload=()=>{
        state.loading=false
        state.error=null
        state.loadingMore=false
        state.isThereMore=true
        state.isReloading=true
        //执行
        if(tempParams)
            execute(tempParams,{isReload:true})
        else
            execute(undefined,{isReload:true})
    }

    //如果手动触发为false,则直接run查询
    if (!manual) run()


    state.run=run

    //加载更多模式不适用局部刷新
    if(!loadMoreMod){
        state.reFresh=reFresh
    }
    //只有加载更多模式下才有的reload 和loadMore
    if(loadMoreMod){
        state.reload=reload
        state.loadMore=loadMore
    }
    return state
}

export {
    useRequest
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值