vue 异步数据呈现方案
起因
当我领会到 写程序的重点在于处理好输入与输出之后 再来写一个搜索组件的时候我关于 loading 的思考如下
什么时候显示 loading ?
- 请求发起后还没有到达的这一段时间
怎么控制视图在这段时间内显示 loading ?
- 使用一个变量来控制
那这个变量属于输入吗?
- 不算,他是一个输出,这个搜索组件的输入只有一个:
searchText
- 不算,他是一个输出,这个搜索组件的输入只有一个:
这个输出的相关的 input、 transform 怎么样的?
- input:searchText -> transform:异步请求 -> output:loading 状态
怎么实现这样的一个 transform?
这个 transform 需要立即的返回状态,没有状态页面上无法确定 loading 怎么显示
- 想到了 promise to object
这个 transform 需要持续的返回新状态。loading 一开始必然是显示,如果之后不返回新状态就没办法关闭了
- 想到了 vue 的计算属性
- 想到了事件机制
这个 transform 还需要返回异步请求的结果。
- object 中新增一个 data 字段用来放结果,还可以有一个 error 字段
- 所以这个 transform 可以当 input 改变时返回一个 object 并且在 依据 input 发起的异步请求成功或者结束后修改之前返回的 object
然后就是在 vue 中实现这样的一个思路
应用的代码长啥样
/读书笔记/vue/vue异步数据呈现方案.html
import { defineComponent, ref } from "vue";
import { usePromiseComputed } from "./lib/vue.composition.api";
export default defineComponent({
setup(props, ctx) {
const searchText = ref("");
const searchResults = usePromiseComputed({
defaultData: [] as string[],
getter() {
return searchApi(searchText.value);
},
});
return { searchText, searchResults };
},
});
这里的 usePromiseComputed
就是之前思考的 transform ,他返回了一个 ref(object)
然后当 searchText
发生变化时会重新执行查询请求 searchApi(searchText.value);
, 当查询请求结束的时候他会修改之前返回的 ref(object)
在模板中
<template>
<input placeholder="请输入你要搜索的关键字" v-model="searchText" />
<div v-if="searchResults.pending">正在查询中</div>
<div v-else-if="searchResults.rejected">
查询失败
{{ searchResults.error }}
</div>
<div v-else-if="searchResults.fulfilled">
<div v-for="(item, index) in searchResults.data" :key="index">
{{ item }}
</div>
</div>
</template>
在这里可以看出来 usePromiseComputed
返回的结果其中的五个字段,三个状态字段也就是 前文中提到的控制loading的那个变量 两个 结果字段
总结
就上面的代码而言是一个极简 input -> tranform -> out 结构。这里不需要手动的声明一个状态变量,然后在不同的阶段在去修改这个变量,这样的操作封装在了 usePromiseComputed
里面。
关于 usePromiseComputed
的实现可以去这里查看 https://github.com/2234839/vue-demo/blob/master/src/components/promise-loading/lib/vue.composition.api.ts
实际上针对业务还加入了两个可选参数 deps 和 dataMergeFun
利用 deps 可以显式的声明哪些变量变化的时候重新请求
利用 dataMergeFun 可以非常简单的在上面的代码基础上加入请求结果翻页功能
by 崮生 from 崮生 • 一些随笔 🎨,欢迎 赞助本文o")
本文欢迎分享与聚合,全文转载未经授权( 联系我)不许可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。