forked from TanStack/query
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseInfiniteQuery.js
More file actions
134 lines (109 loc) · 3.58 KB
/
useInfiniteQuery.js
File metadata and controls
134 lines (109 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import React from 'react'
//
import { useBaseQuery } from './useBaseQuery'
import { getQueryArgs, useGetLatest, handleSuspense } from './utils'
export function useInfiniteQuery(...args) {
const queryInfoRef = React.useRef()
let [queryKey, queryVariables, queryFn, config = {}] = getQueryArgs(args)
const { getFetchMore } = config
const getGetFetchMore = useGetLatest(getFetchMore)
// The default queryFn will query all pages and map them together
const originalQueryFn = queryFn
queryFn = async () => {
const data = []
const pageVariables = [...queryInfoRef.current.query.pageVariables]
const rebuiltPageVariables = []
do {
const args = pageVariables.shift()
if (!data.length) {
// the first page query doesn't need to be rebuilt
data.push(await originalQueryFn(...args))
rebuiltPageVariables.push(args)
} else {
// get an up-to-date cursor based on the previous data set
const nextCursor = getGetFetchMore()(data[data.length - 1], data)
// break early if there's no next cursor
// otherwise we'll start from the beginning
// which will cause unwanted duplication
if (!nextCursor) {
break
}
const pageArgs = [
// remove the last argument (the previously saved cursor)
...args.slice(0, -1),
nextCursor,
]
data.push(await originalQueryFn(...pageArgs))
rebuiltPageVariables.push(pageArgs)
}
} while (pageVariables.length)
queryInfoRef.current.query.canFetchMore = getGetFetchMore()(
data[data.length - 1],
data
)
queryInfoRef.current.query.pageVariables = rebuiltPageVariables
return data
}
const queryInfo = useBaseQuery(queryKey, queryVariables, queryFn, config)
if (
typeof queryInfo.query.canFetchMore === 'undefined' &&
typeof queryInfo.data !== 'undefined'
) {
queryInfo.query.canFetchMore = getGetFetchMore()(
queryInfo.data[queryInfo.data.length - 1],
queryInfo.data
)
}
queryInfoRef.current = queryInfo
let {
refetch,
data = [],
query: { canFetchMore },
} = queryInfo
// Here we seed the pageVariabes for the query
if (!queryInfo.query.pageVariables) {
queryInfo.query.pageVariables = [
[...queryInfo.query.queryKey, ...queryInfo.query.queryVariables],
]
}
const fetchMore = React.useCallback(
(fetchMoreInfo = queryInfoRef.current.query.canFetchMore) =>
queryInfoRef.current.query.canFetchMore
? refetch({
force: true,
__queryFn: async (...args) => {
try {
queryInfoRef.current.query.setState(old => ({
...old,
isFetchingMore: true,
}))
const newArgs = [...args, fetchMoreInfo]
queryInfoRef.current.query.pageVariables.push(newArgs)
const data = [
...queryInfoRef.current.data,
await originalQueryFn(...newArgs),
]
queryInfoRef.current.query.canFetchMore = getGetFetchMore()(
data[data.length - 1],
data
)
return data
} finally {
queryInfoRef.current.query.setState(old => ({
...old,
isFetchingMore: false,
}))
}
},
})
: void 0,
[getGetFetchMore, originalQueryFn, refetch]
)
handleSuspense(queryInfo)
return {
...queryInfo,
data,
canFetchMore,
fetchMore,
}
}