Skip to content

Feature/infinite queries #5004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
aa65b55
feat: remove manual mode for infinite queries
TkDodo Feb 19, 2023
d40fde5
refactor: simplify checking for next / previous fetch
TkDodo Feb 19, 2023
ccf5e76
types: better typings for fetchMeta.direction
TkDodo Feb 19, 2023
e5abed6
refactor: fix hasNextPage / hasPreviousPage
TkDodo Feb 19, 2023
0ce134f
fix: hasNextPage / hasPreviousPage is now always a boolean
TkDodo Feb 19, 2023
c2fbb61
feat: defaultPageParam
TkDodo Feb 19, 2023
bb16db1
types: defaultPageParam is mandatory
TkDodo Feb 19, 2023
d920c84
fix: we also need `defaultPageParam` for `fetchInfiniteQuery` now
TkDodo Feb 19, 2023
f2616e2
test: fix some assertions that relied on `undefined` being in `pagePa…
TkDodo Feb 19, 2023
268813a
add some failing tests to show the problem with pageParam typings
TkDodo Feb 19, 2023
91dd479
feat: add PageParam typing (#5005)
ecyrbe Feb 19, 2023
71c2354
revert changes to pnpm-lock.yaml
TkDodo Feb 19, 2023
5d126ec
types: add TPageParam to other framework adapters
TkDodo Feb 19, 2023
e5a01fd
fix(vue-query): correct generic typing
DamianOsipiuk Feb 21, 2023
736edbd
types: rename InfiniteQueryOptions to InfiniteQueryPageParamsOptions
TkDodo Feb 22, 2023
ee6f8ec
Merge branch 'v5' into feature/infinite-queries
TkDodo Feb 22, 2023
ad980e0
Merge branch 'v5' into feature/infinite-queries
TkDodo Feb 25, 2023
0e382a0
types: add failing select tests
TkDodo Feb 25, 2023
89df288
fix formatting (new prettier version on v5)
TkDodo Feb 25, 2023
3dd7b82
Merge branch 'alpha' into feature/infinite-queries
TkDodo Feb 26, 2023
7209972
types: add types for FetchMeta everywhere
TkDodo Feb 26, 2023
9b1df18
Merge remote-tracking branch 'origin/feature/infinite-queries' into f…
TkDodo Feb 26, 2023
267ee5e
feat(select): defer TData inference (#5040)
ecyrbe Feb 26, 2023
c4f21d7
Merge branch 'alpha' into feature/infinite-queries
TkDodo Feb 26, 2023
825e135
docs: docs for new infinite query features
TkDodo Feb 27, 2023
685be55
docs: examples use new syntax
TkDodo Feb 27, 2023
3bb0c34
Merge branch 'alpha' into feature/infinite-queries
TkDodo Feb 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 10 additions & 41 deletions docs/react/guides/infinite-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,42 +103,11 @@ function Projects() {

When an infinite query becomes `stale` and needs to be refetched, each group is fetched `sequentially`, starting from the first one. This ensures that even if the underlying data is mutated, we're not using stale cursors and potentially getting duplicates or skipping records. If an infinite query's results are ever removed from the queryCache, the pagination restarts at the initial state with only the initial group being requested.

## What if I need to pass custom information to my query function?

By default, the variable returned from `getNextPageParam` will be supplied to the query function, but in some cases, you may want to override this. You can pass custom variables to the `fetchNextPage` function which will override the default variable like so:

[//]: # 'Example3'

```tsx
function Projects() {
const fetchProjects = ({ pageParam = 0 }) =>
fetch('/api/projects?cursor=' + pageParam)

const {
status,
data,
isFetching,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})

// Pass your own page param
const skipToCursor50 = () => fetchNextPage({ pageParam: 50 })
}
```

[//]: # 'Example3'

## What if I want to implement a bi-directional infinite list?

Bi-directional lists can be implemented by using the `getPreviousPageParam`, `fetchPreviousPage`, `hasPreviousPage` and `isFetchingPreviousPage` properties and functions.

[//]: # 'Example4'
[//]: # 'Example3'

```tsx
useInfiniteQuery({
Expand All @@ -149,13 +118,13 @@ useInfiniteQuery({
})
```

[//]: # 'Example4'
[//]: # 'Example3'

## What if I want to show the pages in reversed order?

Sometimes you may want to show the pages in reversed order. If this is case, you can use the `select` option:

[//]: # 'Example5'
[//]: # 'Example4'

```tsx
useInfiniteQuery({
Expand All @@ -168,13 +137,13 @@ useInfiniteQuery({
})
```

[//]: # 'Example5'
[//]: # 'Example4'

## What if I want to manually update the infinite query?

Manually removing first page:

[//]: # 'Example6'
[//]: # 'Example5'

```tsx
queryClient.setQueryData(['projects'], (data) => ({
Expand All @@ -183,11 +152,11 @@ queryClient.setQueryData(['projects'], (data) => ({
}))
```

[//]: # 'Example6'
[//]: # 'Example5'

Manually removing a single value from an individual page:

[//]: # 'Example7'
[//]: # 'Example6'

```tsx
const newPagesArray =
Expand All @@ -201,11 +170,11 @@ queryClient.setQueryData(['projects'], (data) => ({
}))
```

[//]: # 'Example7'
[//]: # 'Example6'

Make sure to keep the same data structure of pages and pageParams!

[//]: # 'Example8'
[//]: # 'Example7'

## What if I want to limit the number of pages?

Expand All @@ -219,7 +188,7 @@ This is made possible by using the `maxPages` option in conjunction with `getNex

In the following example only 3 pages are kept in the query data pages array. If a refetch is needed, only 3 pages will be refetched sequentially.

[//]: # 'Example9'
[//]: # 'Example7'

```tsx
useInfiniteQuery({
Expand Down
22 changes: 21 additions & 1 deletion docs/react/guides/migrating-to-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ This in turn will enable other frameworks to have the same functionality in a fr
import { queryClient } from './my-client'

const { data } = useQuery(
{
{
queryKey: ['users', id],
queryFn: () => fetch(...),
- context: customContext
Expand All @@ -265,6 +265,26 @@ However, refetching all pages might lead to UI inconsistencies. Also, this optio

The v5 includes a new `maxPages` option for infinite queries to limit the number of pages to store in the query data and to refetch. This new feature handles the use cases initially identified for the `refetchPage` page feature without the related issues.

### Infinite queries now need a `defaultPageParam`

Previously, we've passed `undefined` to the `queryFn` as `pageParam`, and you could assign a default value to the `pageParam` parameter in the `queryFn` function signature. This had the drawback of storing `undefined` in the `queryCache`, which is not serializable.

Instead, you now have to pass an explicit `defaultPageParam` to the infinite query options. This will be used as the `pageParam` for the first page:

```diff
useInfiniteQuery({
queryKey,
- queryFn: ({ pageParam = 0 }) => fetchSomething(pageParam),
+ queryFn: ({ pageParam }) => fetchSomething(pageParam),
+ defaultPageParam: 0,
getNextPageParam: (lastPage) => lastPage.next,
})
```

### Manual mode for infinite queries has been removed

Previously, we've allowed to overwrite the `pageParams` that would be returned from `getNextPageParam` or `getPreviousPageParam` by passing a `pageParam` value directly to `fetchNextPage` or `fetchPreviousPage`. This feature didn't work at all with refetches and wasn't widely known or used. This also means that `getNextPagParam` is now required for infinite queries.

[//]: # 'FrameworkBreakingChanges'

## React Query Breaking Changes
Expand Down
12 changes: 8 additions & 4 deletions docs/react/reference/useInfiniteQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const {
...result
} = useInfiniteQuery({
queryKey,
queryFn: ({ pageParam = 1 }) => fetchPage(pageParam),
queryFn: ({ pageParam }) => fetchPage(pageParam),
defaultPageParam: 1,
...options,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
Expand All @@ -30,12 +31,15 @@ The options for `useInfiniteQuery` are identical to the [`useQuery` hook](../ref
- The function that the query will use to request data.
- Receives a [QueryFunctionContext](../guides/query-functions#queryfunctioncontext)
- Must return a promise that will either resolve data or throw an error.
- Make sure you return the data *and* the `pageParam` if needed for use in the props below.
- `getNextPageParam: (lastPage, allPages) => unknown | undefined`
- `defaultPageParam: TPageParam`
- **Required**
- The default page param to use when fetching the first page.
- `getNextPageParam: (lastPage, allPages) => TPageParam | undefined`
- **Required**
- When new data is received for this query, this function receives both the last page of the infinite list of data and the full array of all pages.
- It should return a **single variable** that will be passed as the last optional parameter to your query function.
- Return `undefined` to indicate there is no next page available.
- `getPreviousPageParam: (firstPage, allPages) => unknown | undefined`
- `getPreviousPageParam: (firstPage, allPages) => TPageParam | undefined`
- When new data is received for this query, this function receives both the first page of the infinite list of data and the full array of all pages.
- It should return a **single variable** that will be passed as the last optional parameter to your query function.
- Return `undefined` to indicate there is no previous page available.
Expand Down
21 changes: 2 additions & 19 deletions docs/vue/guides/infinite-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,7 @@ const {
```

[//]: # 'Example'
[//]: # 'Example3'

```tsx
const fetchProjects = ({ pageParam = 0 }) =>
fetch('/api/projects?cursor=' + pageParam)

const { fetchNextPage } = useInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})

// Pass your own page param
const skipToCursor50 = () => fetchNextPage({ pageParam: 50 })
```

[//]: # 'Example3'
[//]: # 'Example7'
[//]: # 'Example6'

```tsx
const newPagesArray =
Expand All @@ -85,4 +68,4 @@ queryClient.setQueryData(['projects'], (data) => ({
}))
```

[//]: # 'Example7'
[//]: # 'Example6'
2 changes: 1 addition & 1 deletion examples/react/algolia/src/algolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SearchOptions = {
export async function search<TData>({
indexName,
query,
pageParam = 0,
pageParam,
hitsPerPage = 10,
}: SearchOptions): Promise<{
hits: Hit<TData>[];
Expand Down
1 change: 1 addition & 0 deletions examples/react/algolia/src/useAlgolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default function useAlgolia<TData>({
queryKey: ["algolia", indexName, query, hitsPerPage],
queryFn: ({ pageParam }) =>
search<TData>({ indexName, query, pageParam, hitsPerPage }),
defaultPageParam: 0,
getNextPageParam: (lastPage) => lastPage?.nextPage,
staleTime,
cacheTime,
Expand Down
3 changes: 2 additions & 1 deletion examples/react/infinite-query-with-max-pages/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ function Example() {
hasPreviousPage,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam = 0 }) => {
queryFn: async ({ pageParam }) => {
const res = await axios.get('/api/projects?cursor=' + pageParam)
return res.data
},
defaultPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
maxPages: 3,
Expand Down
3 changes: 2 additions & 1 deletion examples/react/load-more-infinite-scroll/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ function Example() {
hasPreviousPage,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam = 0 }) => {
queryFn: async ({ pageParam }) => {
const res = await axios.get('/api/projects?cursor=' + pageParam)
return res.data
},
defaultPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
})
Expand Down
Loading