Skip to content

Commit c4a8a12

Browse files
committed
feat: add useQueryState hook
1 parent 013078b commit c4a8a12

File tree

3 files changed

+76
-16
lines changed

3 files changed

+76
-16
lines changed

packages/react-query/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export {
4040
} from './QueryErrorResetBoundary'
4141
export { useIsFetching } from './useIsFetching'
4242
export { useIsMutating, useMutationState } from './useMutationState'
43+
export { useQueryState } from './useQueryState'
4344
export { useMutation } from './useMutation'
4445
export { useInfiniteQuery } from './useInfiniteQuery'
4546
export { useIsRestoring, IsRestoringProvider } from './isRestoring'
Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
'use client'
2-
import * as React from 'react'
3-
import { notifyManager } from '@tanstack/query-core'
4-
5-
import { useQueryClient } from './QueryClientProvider'
2+
import { useQueryState } from './useQueryState'
63
import type { QueryClient, QueryFilters } from '@tanstack/query-core'
74

85
export function useIsFetching(
96
filters?: QueryFilters,
107
queryClient?: QueryClient,
118
): number {
12-
const client = useQueryClient(queryClient)
13-
const queryCache = client.getQueryCache()
14-
15-
return React.useSyncExternalStore(
16-
React.useCallback(
17-
(onStoreChange) =>
18-
queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),
19-
[queryCache],
20-
),
21-
() => client.isFetching(filters),
22-
() => client.isFetching(filters),
23-
)
9+
return useQueryState(
10+
{ filters: { ...filters, fetchStatus: 'fetching' } },
11+
queryClient,
12+
).length
2413
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use client'
2+
import * as React from 'react'
3+
4+
import { notifyManager, replaceEqualDeep } from '@tanstack/query-core'
5+
import { useQueryClient } from './QueryClientProvider'
6+
import type {
7+
DefaultError,
8+
Query,
9+
QueryCache,
10+
QueryClient,
11+
QueryFilters,
12+
QueryKey,
13+
QueryState,
14+
} from '@tanstack/query-core'
15+
16+
type QueryStateOptions<TResult = QueryState> = {
17+
filters?: QueryFilters
18+
select?: (query: Query<unknown, DefaultError, unknown, QueryKey>) => TResult
19+
}
20+
21+
function getResult<TResult = QueryState>(
22+
queryCache: QueryCache,
23+
options: QueryStateOptions<TResult>,
24+
): Array<TResult> {
25+
return queryCache
26+
.findAll(options.filters)
27+
.map(
28+
(query): TResult =>
29+
(options.select
30+
? options.select(
31+
query as Query<unknown, DefaultError, unknown, QueryKey>,
32+
)
33+
: query.state) as TResult,
34+
)
35+
}
36+
37+
export function useQueryState<TResult = QueryState>(
38+
options: QueryStateOptions<TResult> = {},
39+
queryClient?: QueryClient,
40+
): Array<TResult> {
41+
const queryCache = useQueryClient(queryClient).getQueryCache()
42+
const optionsRef = React.useRef(options)
43+
const result = React.useRef<Array<TResult>>()
44+
if (!result.current) {
45+
result.current = getResult(queryCache, options)
46+
}
47+
48+
React.useEffect(() => {
49+
optionsRef.current = options
50+
})
51+
52+
return React.useSyncExternalStore(
53+
React.useCallback(
54+
(onStoreChange) =>
55+
queryCache.subscribe(() => {
56+
const nextResult = replaceEqualDeep(
57+
result.current,
58+
getResult(queryCache, optionsRef.current),
59+
)
60+
if (result.current !== nextResult) {
61+
result.current = nextResult
62+
notifyManager.schedule(onStoreChange)
63+
}
64+
}),
65+
[queryCache],
66+
),
67+
() => result.current,
68+
() => result.current,
69+
)!
70+
}

0 commit comments

Comments
 (0)