无限加载
有时我们想构建一个无限加载的界面,通过一个 "Load More" 按钮向列表追加数据(或者当你滚动时自动加载):
Quaere 提供了一个专用 API queryWithInfinite 来支持常见的 UI 模式,比如 分页 和 无限加载。
queryWithInfinite
queryWithInfinite 让我们能够通过一个 Hook 触发多个请求。就像下面这样:
const projectsQuery = queryWithInfinite({
fetcher: (variables, { pageParam }) =>
axios.get(`/api/projects`, {
...variables,
page: pageParam,
}),
initialPageParam: 0,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, pages) => firstPage.prevCursor,
...options,
});
// ...
const {
isFetchingNextPage,
isFetchingPreviousPage,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
...result
} = useQuery({ query: projectsQuery });API
返回值
当 useQuery 传入 queryWithInfinite 与传入 query 时的返回值完全相同,只是新增了以下内容:
-
data.pages: TData[]- 包含所有页面的数组。
-
data.pageParams: number[]- 包含所有页面参数的数组。
-
isFetchingNextPage: boolean- 在使用
fetchNextPage请求下一页时为true。
- 在使用
-
isFetchingPreviousPage: boolean- 在使用
fetchPreviousPage请求上一页时为true。
- 在使用
-
fetchNextPage: (options?: FetchNextPageOptions) => Promise<TData>- 此函数允许您请求下一页的结果。
options.cancelRefetch: boolean,如果设置为true,多次调用fetchNextPage将每次调用fetchPage,无论之前的调用是否已解决。同时,忽略之前调用的结果。如果设置为false,多次调用fetchNextPage在第一个调用未解决之前不会产生任何影响。默认值为true。
-
fetchPreviousPage: (options?: FetchPreviousPageOptions) => Promise<TData>- 此函数允许您请求上一页的结果。
options.cancelRefetch: boolean,与fetchNextPage相同。
-
hasNextPage: boolean- 如果有下一页要请求(通过
getNextPageParam选项得知),则为true。
- 如果有下一页要请求(通过
-
hasPreviousPage: boolean- 如果有上一页要请求(通过
getPreviousPageParam选项得知),则为true。
- 如果有上一页要请求(通过
选项
queryWithInfinite 的选项与 query 钩子完全相同,只是新增了以下内容:
-
initialPageParam: number- 必需
- 请求第一页时使用的默认页参数。
-
getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) => number | undefined | null- 必需
- 当接收到此查询的新数据时,该函数接收无限数据列表的最后一页和所有页面的完整数组,以及页参数信息。
- 应返回一个数字,该数字将作为您查询函数的最后一个可选参数传递。
- 返回
undefined或null表示没有下一页可用。
-
getPreviousPageParam: (firstPage, allPages, firstPageParam, allPageParams) => number | undefined | null- 当接收到此查询的新数据时,该函数接收无限数据列表的第一页和所有页面的完整数组,以及页参数信息。
- 应返回一个数字,该数字将作为您查询函数的最后一个可选参数传递。
- 返回
undefined或null表示没有上一页可用。
示例
import { useQuery } from "quaere";
const projectsQuery = queryWithInfinite({
fetcher: (variables, { pageParam }) =>
axios.get(`/api/projects`, {
...variables,
cursor: pageParam,
}),
initialPageParam: 0,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
});
function Projects() {
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
isLoading,
} = useQuery({
query: projectsQuery,
});
return isLoading ? (
<p>Loading...</p>
) : status === "error" ? (
<p>Error: {error.message}</p>
) : (
<>
{data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.data.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? "Loading more..."
: hasNextPage
? "Load More"
: "Nothing more to load"}
</button>
</div>
<div>{isFetching && !isFetchingNextPage ? "Fetching..." : null}</div>
</>
);
}