chore: add demo for apiComponent with caching and concurrency (#5827)

* chore: add demo for apiComponent with caching and concurrency

* docs: update api component docs
pull/78/MERGE
Netfan 2025-03-31 11:51:57 +08:00 committed by GitHub
parent 06ccad9db0
commit 166e9a0e82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 88 additions and 1 deletions

View File

@ -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 |

View File

@ -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>

View File

@ -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>