Skip to content

Commit

Permalink
feat: tanstack query demos (#4276)
Browse files Browse the repository at this point in the history
* chore(@vben/request): add axios-retry

* feat: error retry

* feat: paginated queries

* feat: infinite queries

* chore: update

* chore: update

* fix: ci error

* chore: update

* chore: remove axios-retry

* chore: update deps

* chore: update deps

* chore: update deps

* chore: update pnpm.lock

---------

Co-authored-by: vince <vince292007@gmail.com>
  • Loading branch information
likui628 and vince292007 committed Sep 8, 2024
1 parent 56e6619 commit 86ed732
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 0 deletions.
1 change: 1 addition & 0 deletions playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"#/*": "./src/*"
},
"dependencies": {
"@tanstack/vue-query": "^5.53.1",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*",
Expand Down
5 changes: 5 additions & 0 deletions playground/src/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { initStores } from '@vben/stores';
import '@vben/styles';
import '@vben/styles/antd';

import { VueQueryPlugin } from '@tanstack/vue-query';

import { setupI18n } from '#/locales';

import App from './app.vue';
Expand All @@ -25,6 +27,9 @@ async function bootstrap(namespace: string) {
// 配置路由及路由守卫
app.use(router);

// 配置@tanstack/vue-query
app.use(VueQueryPlugin);

app.mount('#app');
}

Expand Down
9 changes: 9 additions & 0 deletions playground/src/router/routes/modules/demos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ const routes: RouteRecordRaw[] = [
title: $t('page.demos.features.clipboard'),
},
},
{
name: 'VueQueryDemo',
path: '/demos/features/vue-query',
component: () =>
import('#/views/demos/features/vue-query/index.vue'),
meta: {
title: 'Tanstack Query',
},
},
],
},
// 面包屑导航
Expand Down
25 changes: 25 additions & 0 deletions playground/src/views/demos/features/vue-query/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { Card } from 'ant-design-vue';
import InfiniteQueries from './infinite-queries.vue';
import PaginatedQueries from './paginated-queries.vue';
import QueryRetries from './query-retries.vue';
</script>

<template>
<Page title="Vue Query示例">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<Card title="分页查询">
<PaginatedQueries />
</Card>
<Card title="无限滚动">
<InfiniteQueries class="h-[300px] overflow-auto" />
</Card>
<Card title="错误重试">
<QueryRetries />
</Card>
</div>
</Page>
</template>
58 changes: 58 additions & 0 deletions playground/src/views/demos/features/vue-query/infinite-queries.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script setup lang="ts">
import type { IProducts } from './typing';
import { useInfiniteQuery } from '@tanstack/vue-query';
import { Button } from 'ant-design-vue';
const LIMIT = 10;
const fetchProducts = async ({ pageParam = 0 }): Promise<IProducts> => {
const res = await fetch(
`https://dummyjson.com/products?limit=${LIMIT}&skip=${pageParam * LIMIT}`,
);
return res.json();
};
const {
data,
error,
fetchNextPage,
hasNextPage,
isError,
isFetching,
isFetchingNextPage,
isPending,
} = useInfiniteQuery({
getNextPageParam: (current, allPages) => {
const nextPage = allPages.length + 1;
const lastPage = current.skip + current.limit;
if (lastPage === current.total) return;
return nextPage;
},
initialPageParam: 0,
queryFn: fetchProducts,
queryKey: ['products'],
});
</script>

<template>
<div>
<span v-if="isPending">加载...</span>
<span v-else-if="isError">出错了: {{ error }}</span>
<div v-else-if="data">
<span v-if="isFetching && !isFetchingNextPage">Fetching...</span>
<ul v-for="(group, index) in data.pages" :key="index">
<li v-for="product in group.products" :key="product.id">
{{ product.title }}
</li>
</ul>
<Button
:disabled="!hasNextPage || isFetchingNextPage"
@click="() => fetchNextPage()"
>
<span v-if="isFetchingNextPage">加载中...</span>
<span v-else-if="hasNextPage">加载更多</span>
<span v-else>没有更多了</span>
</Button>
</div>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
import type { IProducts } from './typing';
import { type Ref, ref } from 'vue';
import { keepPreviousData, useQuery } from '@tanstack/vue-query';
import { Button } from 'ant-design-vue';
const LIMIT = 10;
const fetcher = async (page: Ref<number>): Promise<IProducts> => {
const res = await fetch(
`https://dummyjson.com/products?limit=${LIMIT}&skip=${(page.value - 1) * LIMIT}`,
);
return res.json();
};
const page = ref(1);
const { data, error, isError, isPending, isPlaceholderData } = useQuery({
// The data from the last successful fetch is available while new data is being requested.
placeholderData: keepPreviousData,
queryFn: () => fetcher(page),
queryKey: ['products', page],
});
const prevPage = () => {
page.value = Math.max(page.value - 1, 1);
};
const nextPage = () => {
if (!isPlaceholderData.value) {
page.value = page.value + 1;
}
};
</script>

<template>
<div class="flex gap-4">
<Button size="small" @click="prevPage">上一页</Button>
<p>当前页: {{ page }}</p>
<Button size="small" @click="nextPage">下一页</Button>
</div>
<div class="p-4">
<div v-if="isPending">加载中...</div>
<div v-else-if="isError">出错了: {{ error }}</div>
<div v-else-if="data">
<ul>
<li v-for="item in data.products" :key="item.id">
{{ item.title }}
</li>
</ul>
</div>
</div>
</template>
34 changes: 34 additions & 0 deletions playground/src/views/demos/features/vue-query/query-retries.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import { Button } from 'ant-design-vue';
const count = ref(-1);
async function fetchApi() {
count.value += 1;
return new Promise((_resolve, reject) => {
setTimeout(() => {
reject(new Error('something went wrong!'));
}, 1000);
});
}
const { error, isFetching, refetch } = useQuery({
enabled: false, // Disable automatic refetching when the query mounts
queryFn: fetchApi,
queryKey: ['queryKey'],
retry: 3, // Will retry failed requests 3 times before displaying an error
});
const onClick = async () => {
count.value = -1;
await refetch();
};
</script>

<template>
<Button :loading="isFetching" @click="onClick"> 发起错误重试 </Button>
<p v-if="count > 0" class="my-3">重试次数{{ count }}</p>
<p>{{ error }}</p>
</template>
18 changes: 18 additions & 0 deletions playground/src/views/demos/features/vue-query/typing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface IProducts {
limit: number;
products: {
brand: string;
category: string;
description: string;
discountPercentage: string;
id: string;
images: string[];
price: string;
rating: string;
stock: string;
thumbnail: string;
title: string;
}[];
skip: number;
total: number;
}
38 changes: 38 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 86ed732

Please sign in to comment.