分页/滞后查询 Paginated Queries
呈现分页数据是一种非常常见的 UI 模式,在 Vue Query 中,它可以简单的通过在查询键中包含页面信息来"正常工作":
TypeScript
1const result = useQuery(["projects", page], fetchProjects);但是,如果运行该示例,你可能会注意到一些奇怪的事情:
UI 在success和loading状态之间来回跳转,因为每个新页面都被视为一个全新的查询。
这种体验并不是最佳的,不幸的是,今天有不少工具在坚持使用。
但不是 Vue Query!
你可能已经猜到了,Vue Query 带有一个称为keepPreviousData的强大功能,从而使得这个问题可以被轻易的解决。
使用keepPreviousData的更好的分页查询
考虑下面的例子,在理想情况下,我们希望为查询增加 pageIndex(或游标)。
如果使用useQuery,从技术上讲它仍然可以正常工作,但是 UI 会随着每个页面或游标创建和销毁不同的查询而跳出 success 和 loading 状态。
通过将keepPreviousData设置为true,我们可以得到一些新的东西:
- 请求新数据时,即使查询键值已更改,上次成功获取的数据仍可用
- 当新数据到达时,先前的数据将被无缝交换以显示新数据
- 可以使用
isPreviousData来了解当前查询提供的是什么数据
HTML
1<script setup lang="ts">2 import { ref, Ref } from "vue";3 import { useQuery } from "@tanstack/vue-query";45 const fetcher = (page: Ref<number>) =>6 fetch(7 `https://jsonplaceholder.typicode.com/posts?_page=${page.value}&_limit=10`8 ).then((response) => response.json());910 const page = ref(1);11 const { isLoading, isError, data, error, isFetching, isPreviousData } =12 useQuery({13 queryKey: ["projects", page],14 queryFn: () => fetcher(page),15 keepPreviousData: true,16 });17 const prevPage = () => {18 page.value = Math.max(page.value - 1, 1);19 };20 const nextPage = () => {21 if (!isPreviousData.value) {22 page.value = page.value + 1;23 }24 };25</script>26 27<template>28 <h1>Posts</h1>29 <p>Current Page: {{ page }} | Previous data: {{ isPreviousData }}</p>30 <button @click="prevPage">Prev Page</button>31 <button @click="nextPage">Next Page</button>32 <div v-if="isLoading">Loading...</div>33 <div v-else-if="isError">An error has occurred: {{ error }}</div>34 <div v-else-if="data">35 <ul>36 <li v-for="item in data" :key="item.id">{{ item.title }}</li>37 </ul>38 </div>39</template>使用keepPreviousData滞后无限查询的结果
尽管不那么常见,但是keepPreviousData选项也可以与useInfiniteQueryHook 完美配合,所以你可以无缝地允许你的用户继续查看缓存的数据,而无限查询的键值将随着时间变化而自动变化。