chore: add demo for apiComponent with caching and concurrency (#5827)
* chore: add demo for apiComponent with caching and concurrency * docs: update api component docspull/78/MERGE
parent
06ccad9db0
commit
166e9a0e82
|
@ -123,6 +123,10 @@ function fetchApi(): Promise<Record<string, any>> {
|
|||
|
||||
:::
|
||||
|
||||
## 并发和缓存
|
||||
|
||||
有些场景下可能需要使用多个ApiComponent,它们使用了相同的远程数据源(例如用在可编辑的表格中)。如果直接将请求后端接口的函数传递给api属性,则每一个实例都会访问一次接口,这会造成资源浪费,是完全没有必要的。Tanstack Query提供了并发控制、缓存、重试等诸多特性,我们可以将接口请求函数用useQuery包装一下再传递给ApiComponent,这样的话无论页面有多少个使用相同数据源的ApiComponent实例,都只会发起一次远程请求。演示效果请参考 [Playground vue-query](http://localhost:5555/demos/features/vue-query),具体代码请查看项目文件[concurrency-caching](https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/views/demos/features/vue-query/concurrency-caching.vue)
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
@ -147,3 +151,10 @@ function fetchApi(): Promise<Record<string, any>> {
|
|||
| options | 直接传入选项数据,也作为api返回空数据时的后备数据 | `OptionsItem[]` | - |
|
||||
| visibleEvent | 触发重新请求数据的事件名 | `string` | - |
|
||||
| loadingSlot | 目标组件的插槽名称,用来显示一个"加载中"的图标 | `string` | - |
|
||||
|
||||
### Methods
|
||||
|
||||
| 方法 | 描述 | 类型 | 版本要求 |
|
||||
| --- | --- | --- | --- |
|
||||
| getComponentRef | 获取被包装的组件的实例 | ()=>T | >5.5.4 |
|
||||
| updateParam | 设置接口请求参数(将与params属性合并) | (newParams: Record<string, any>)=>void | >5.5.4 |
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<script lang="ts" setup>
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { useQuery } from '@tanstack/vue-query';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { getMenuList } from '#/api';
|
||||
|
||||
const queryKey = ['demo', 'api', 'options'];
|
||||
const count = 4;
|
||||
|
||||
const { dataUpdatedAt, promise: fetchDataFn } = useQuery({
|
||||
// 在组件渲染期间预取数据
|
||||
experimental_prefetchInRender: true,
|
||||
// 获取接口数据的函数
|
||||
queryFn: getMenuList,
|
||||
queryKey,
|
||||
// 每次组件挂载时都重新获取数据。如果不需要每次都重新获取就不要设置为always
|
||||
refetchOnMount: 'always',
|
||||
// 缓存时间
|
||||
staleTime: 1000 * 60 * 5,
|
||||
});
|
||||
|
||||
async function fetchOptions() {
|
||||
return await fetchDataFn.value;
|
||||
}
|
||||
|
||||
const schema = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
schema.push({
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: fetchOptions,
|
||||
class: 'w-full',
|
||||
filterOption: (input: string, option: Recordable<any>) => {
|
||||
return option.label.toLowerCase().includes(input.toLowerCase());
|
||||
},
|
||||
labelField: 'name',
|
||||
showSearch: true,
|
||||
valueField: 'id',
|
||||
},
|
||||
fieldName: `field${i}`,
|
||||
label: `Select ${i}`,
|
||||
});
|
||||
}
|
||||
|
||||
const [Form] = useVbenForm({
|
||||
schema,
|
||||
showDefaultActions: false,
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-2 flex gap-2">
|
||||
<div>以下{{ count }}个组件共用一个数据源。</div>
|
||||
<div>缓存更新时间:{{ new Date(dataUpdatedAt).toLocaleString() }}</div>
|
||||
</div>
|
||||
<Form />
|
||||
</div>
|
||||
</template>
|
|
@ -1,11 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { refAutoReset } from '@vueuse/core';
|
||||
import { Button, Card, Empty } from 'ant-design-vue';
|
||||
|
||||
import ConcurrencyCaching from './concurrency-caching.vue';
|
||||
import InfiniteQueries from './infinite-queries.vue';
|
||||
import PaginatedQueries from './paginated-queries.vue';
|
||||
import QueryRetries from './query-retries.vue';
|
||||
|
||||
const showCaching = refAutoReset(true, 1000);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -20,6 +24,17 @@ import QueryRetries from './query-retries.vue';
|
|||
<Card title="错误重试">
|
||||
<QueryRetries />
|
||||
</Card>
|
||||
<Card
|
||||
title="并发和缓存"
|
||||
v-spinning="!showCaching"
|
||||
:body-style="{ minHeight: '330px' }"
|
||||
>
|
||||
<template #extra>
|
||||
<Button @click="showCaching = false">重新加载</Button>
|
||||
</template>
|
||||
<ConcurrencyCaching v-if="showCaching" />
|
||||
<Empty v-else description="正在加载..." />
|
||||
</Card>
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue