Skip to content

Commit 8ba00e6

Browse files
authored
fix(react-query): fix queryFn for useRefetchInterval (#25)
1 parent 1c946c0 commit 8ba00e6

File tree

17 files changed

+171
-178
lines changed

17 files changed

+171
-178
lines changed

src/core/types/DataManger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {AnyDataSource, DataSourceParams, DataSourceTag} from './DataSource'
33

44
export interface DataManager {
55
invalidateTag(tag: DataSourceTag, invalidateOptions?: InvalidateOptions): Promise<void>;
6+
67
invalidateTags(tags: DataSourceTag[], invalidateOptions?: InvalidateOptions): Promise<void>;
78

89
invalidateSource<TDataSource extends AnyDataSource>(

src/core/utils/getError.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export const getError = <T>(states: {error: T | null}[]) => {
1+
export const getError = <T>(states: {error: T | null}[]): NonNullable<T> | null => {
22
return states.find(({error}) => Boolean(error))?.error ?? null;
33
};

src/core/utils/getStatus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import type {DataLoaderStatus} from '../types/DataLoaderStatus';
22

33
import {mergeStatuses} from './mergeStatuses';
44

5-
export const getStatus = (states: {status: DataLoaderStatus}[]) => {
5+
export const getStatus = (states: {status: DataLoaderStatus}[]): DataLoaderStatus => {
66
return mergeStatuses(states.map(({status}) => status));
77
};

src/core/utils/hasTag.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {DataSourceKey, DataSourceTag} from '../types/DataSource';
22

3-
export const hasTag = (key: DataSourceKey, tag: DataSourceTag) => {
3+
export const hasTag = (key: DataSourceKey, tag: DataSourceTag): boolean => {
44
if (!Array.isArray(key)) {
55
return false;
66
}

src/react-query/ClientDataManager.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,27 +109,24 @@ export class ClientDataManager implements DataManager {
109109
);
110110
}
111111

112-
private invalidateQueries(
112+
protected invalidateQueries(
113113
filters: InvalidateQueryFilters,
114114
invalidateOptions?: InvalidateOptions,
115115
) {
116-
const {repeat} = invalidateOptions || {};
117-
118116
const invalidate = () => this.queryClient.invalidateQueries(filters);
119117

120-
this.repeatInvalidate(invalidate, repeat);
118+
this.repeatInvalidate(invalidate, invalidateOptions?.repeat);
121119

122120
return invalidate();
123121
}
124122

125-
private repeatInvalidate(invalidate: () => Promise<void>, repeat?: InvalidateRepeatOptions) {
123+
protected repeatInvalidate(invalidate: () => Promise<void>, repeat?: InvalidateRepeatOptions) {
126124
if (!repeat) {
127125
return;
128126
}
129-
const {interval, count} = repeat;
130127

131-
for (let i = 1; i <= count; i++) {
132-
setTimeout(invalidate, interval * i);
128+
for (let i = 1; i <= repeat.count; i++) {
129+
setTimeout(invalidate, repeat.interval * i);
133130
}
134131
}
135132
}

src/react-query/hooks/useQueryContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {useMemo} from 'react';
22

33
import {useQueryClient} from '@tanstack/react-query';
44

5-
import type {QueryDataSourceContext} from '../types';
5+
import type {QueryDataSourceContext} from '../types/base';
66

77
export const useQueryContext = (): QueryDataSourceContext => {
88
const queryClient = useQueryClient();

src/react-query/hooks/useQueryData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {useInfiniteQueryData} from '../impl/infinite/hooks';
33
import type {AnyInfiniteQueryDataSource} from '../impl/infinite/types';
44
import {usePlainQueryData} from '../impl/plain/hooks';
55
import type {AnyPlainQueryDataSource} from '../impl/plain/types';
6-
import type {AnyQueryDataSource} from '../types';
6+
import type {AnyQueryDataSource} from '../types/base';
77
import {notReachable} from '../utils/notReachable';
88

99
import {useQueryContext} from './useQueryContext';
Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,69 @@
11
import React from 'react';
22

3-
import type {Query, QueryFunction, QueryFunctionContext, SkipToken} from '@tanstack/react-query';
4-
5-
import type {DataSourceError, DataSourceKey, DataSourceResponse} from '../../core';
6-
import type {AnyQueryDataSource, RefetchInterval} from '../types';
7-
8-
export const useRefetchInterval = <TDataSource extends AnyQueryDataSource, TQueryData, TPageParams>(
9-
refetchIntervalOption?: RefetchInterval<
10-
DataSourceResponse<TDataSource>,
11-
DataSourceError<TDataSource>,
12-
TQueryData,
13-
DataSourceKey
14-
>,
15-
queryFnOption?:
16-
| QueryFunction<DataSourceResponse<TDataSource>, DataSourceKey, TPageParams>
17-
| SkipToken,
18-
): {
3+
import type {DefaultError, Query, QueryFunction, QueryKey, SkipToken} from '@tanstack/react-query';
4+
5+
import type {RefetchInterval} from '../types/refetch-interval';
6+
7+
export interface UseRefetchIntervalResult<
8+
TQueryFnData = unknown,
9+
TError = DefaultError,
10+
TQueryData = TQueryFnData,
11+
TQueryKey extends QueryKey = QueryKey,
12+
TPageParam = never,
13+
> {
1914
refetchInterval?:
2015
| number
2116
| false
2217
| ((
23-
query: Query<
24-
DataSourceResponse<TDataSource>,
25-
DataSourceError<TDataSource>,
26-
TQueryData,
27-
DataSourceKey
28-
>,
18+
query: Query<TQueryFnData, TError, TQueryData, TQueryKey>,
2919
) => number | false | undefined);
30-
queryFn?:
31-
| QueryFunction<DataSourceResponse<TDataSource>, DataSourceKey, TPageParams>
32-
| SkipToken;
33-
} => {
20+
queryFn?: QueryFunction<TQueryFnData, TQueryKey, TPageParam> | SkipToken;
21+
}
22+
23+
export const useRefetchInterval = <
24+
TQueryFnData = unknown,
25+
TError = DefaultError,
26+
TQueryData = TQueryFnData,
27+
TQueryKey extends QueryKey = QueryKey,
28+
TPageParam = never,
29+
>(
30+
refetchInterval?: RefetchInterval<TQueryFnData, TError, TQueryData, TQueryKey>,
31+
queryFn?: QueryFunction<TQueryFnData, TQueryKey, TPageParam> | SkipToken,
32+
): UseRefetchIntervalResult<TQueryFnData, TError, TQueryData, TQueryKey, TPageParam> => {
3433
const count = React.useRef<number>(0);
3534

36-
const queryFn = React.useMemo(() => {
37-
if (typeof queryFnOption === 'function') {
38-
return (context: QueryFunctionContext<DataSourceKey, TPageParams>) => {
39-
count.current++;
40-
return queryFnOption(context);
41-
};
35+
const actualQueryFn = React.useMemo(() => {
36+
if (typeof queryFn === 'function') {
37+
return ((context) => {
38+
++count.current;
39+
return queryFn(context);
40+
}) satisfies UseRefetchIntervalResult<
41+
TQueryFnData,
42+
TError,
43+
TQueryData,
44+
TQueryKey,
45+
TPageParam
46+
>['queryFn'];
4247
}
43-
return undefined;
44-
}, [queryFnOption]);
45-
46-
const refetchInterval = React.useMemo(() => {
47-
if (typeof refetchIntervalOption === 'function') {
48-
return (
49-
query: Query<
50-
DataSourceResponse<TDataSource>,
51-
DataSourceError<TDataSource>,
52-
TQueryData,
53-
DataSourceKey
54-
>,
55-
) => {
56-
return refetchIntervalOption(query, count.current);
57-
};
48+
49+
return queryFn;
50+
}, [queryFn]);
51+
52+
const actualRefetchInterval = React.useMemo(() => {
53+
if (typeof refetchInterval === 'function') {
54+
return ((query) => {
55+
return refetchInterval(query, count.current);
56+
}) satisfies UseRefetchIntervalResult<
57+
TQueryFnData,
58+
TError,
59+
TQueryData,
60+
TQueryKey,
61+
TPageParam
62+
>['refetchInterval'];
5863
}
59-
return refetchIntervalOption;
60-
}, [refetchIntervalOption]);
6164

62-
return {refetchInterval, queryFn};
65+
return refetchInterval;
66+
}, [refetchInterval]);
67+
68+
return {queryFn: actualQueryFn, refetchInterval: actualRefetchInterval};
6369
};

src/react-query/impl/infinite/hooks.ts

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,69 +10,64 @@ import type {
1010
DataSourceKey,
1111
DataSourceOptions,
1212
DataSourceParams,
13+
DataSourceRequest,
1314
DataSourceResponse,
1415
DataSourceState,
1516
} from '../../../core';
1617
import {useRefetchInterval} from '../../hooks/useRefetchInterval';
1718
import {normalizeStatus} from '../../utils/normalizeStatus';
1819

19-
import type {
20-
AnyInfiniteQueryDataSource,
21-
AnyPageParam,
22-
InfiniteQueryObserverExtendedOptions,
23-
} from './types';
20+
import type {AnyInfiniteQueryDataSource, InfiniteQueryObserverExtendedOptions} from './types';
2421
import {composeOptions} from './utils';
2522

26-
export const useInfiniteQueryData = <TDataSource extends AnyInfiniteQueryDataSource>(
27-
context: DataSourceContext<TDataSource>,
28-
dataSource: TDataSource,
29-
params: DataSourceParams<TDataSource>,
30-
options?: Partial<DataSourceOptions<TDataSource>>,
31-
): DataSourceState<TDataSource> => {
32-
const composedOptions = composeOptions(context, dataSource, params, options);
33-
34-
const extendedOptions = useInfiniteQueryDataOptions(composedOptions);
35-
36-
const result = useInfiniteQuery(extendedOptions);
37-
38-
const transformedData = useMemo<DataSourceState<TDataSource>['data']>(
39-
() => result.data?.pages.flat(1) ?? [],
40-
[result.data],
41-
);
42-
43-
return {
44-
...result,
45-
status: normalizeStatus(result.status, result.fetchStatus),
46-
data: transformedData,
47-
originalStatus: result.status,
48-
originalData: result.data,
49-
} as DataSourceState<TDataSource>;
50-
};
51-
52-
export function useInfiniteQueryDataOptions<TDataSource extends AnyInfiniteQueryDataSource>(
23+
const useInfiniteQueryDataOptions = <TDataSource extends AnyInfiniteQueryDataSource>(
5324
composedOptions: InfiniteQueryObserverExtendedOptions<
5425
DataSourceResponse<TDataSource>,
5526
DataSourceError<TDataSource>,
56-
InfiniteData<DataSourceData<TDataSource>, AnyPageParam>,
27+
InfiniteData<DataSourceData<TDataSource>, Partial<DataSourceRequest<TDataSource>>>,
5728
DataSourceResponse<TDataSource>,
5829
DataSourceKey,
59-
AnyPageParam
30+
Partial<DataSourceRequest<TDataSource>>
6031
>,
6132
): InfiniteQueryObserverOptions<
6233
DataSourceResponse<TDataSource>,
6334
DataSourceError<TDataSource>,
64-
InfiniteData<DataSourceData<TDataSource>, AnyPageParam>,
35+
InfiniteData<DataSourceData<TDataSource>, Partial<DataSourceRequest<TDataSource>>>,
6536
DataSourceResponse<TDataSource>,
6637
DataSourceKey,
67-
AnyPageParam
68-
> {
38+
Partial<DataSourceRequest<TDataSource>>
39+
> => {
6940
const {
70-
refetchInterval: refetchIntervalOption,
7141
queryFn: queryFnOption,
42+
refetchInterval: refetchIntervalOption,
7243
...restOptions
73-
} = composedOptions || {};
44+
} = composedOptions;
45+
46+
const {queryFn, refetchInterval} = useRefetchInterval(refetchIntervalOption, queryFnOption);
47+
48+
return {...restOptions, queryFn, refetchInterval};
49+
};
50+
51+
export const useInfiniteQueryData = <TDataSource extends AnyInfiniteQueryDataSource>(
52+
context: DataSourceContext<TDataSource>,
53+
dataSource: TDataSource,
54+
params: DataSourceParams<TDataSource>,
55+
options?: Partial<DataSourceOptions<TDataSource>>,
56+
): DataSourceState<TDataSource> => {
57+
const extendedOptions = composeOptions(context, dataSource, params, options);
58+
const composedOptions = useInfiniteQueryDataOptions(extendedOptions);
59+
const state = useInfiniteQuery(composedOptions);
7460

75-
const {refetchInterval, queryFn} = useRefetchInterval(refetchIntervalOption, queryFnOption);
61+
const transformedData = useMemo<DataSourceState<TDataSource>['data']>(
62+
() => state.data?.pages.flat(1) ?? [],
63+
[state.data],
64+
);
7665

77-
return {...restOptions, refetchInterval, queryFn};
78-
}
66+
return {
67+
...state,
68+
status: normalizeStatus(state.status, state.fetchStatus),
69+
data: transformedData,
70+
originalStatus: state.status,
71+
originalData: state.data,
72+
} as DataSourceState<TDataSource>;
73+
};

src/react-query/impl/infinite/types.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
import type {
22
DefaultError,
33
InfiniteData,
4+
InfiniteQueryObserverOptions,
45
InfiniteQueryObserverResult,
5-
InfiniteQueryPageParamsOptions,
66
QueryFunctionContext,
77
QueryKey,
88
} from '@tanstack/react-query';
99
import type {Overwrite} from 'utility-types';
1010

1111
import type {ActualData, DataLoaderStatus, DataSource, DataSourceKey} from '../../../core';
12-
import type {QueryDataSourceContext} from '../../types';
13-
import type {QueryObserverExtendedOptions} from '../plain/types';
12+
import type {QueryDataSourceContext} from '../../types/base';
13+
import type {QueryDataAdditionalOptions} from '../../types/options';
1414

15-
export interface InfiniteQueryObserverExtendedOptions<
15+
export type InfiniteQueryObserverExtendedOptions<
1616
TQueryFnData = unknown,
1717
TError = DefaultError,
1818
TData = TQueryFnData,
1919
TQueryData = TQueryFnData,
2020
TQueryKey extends QueryKey = QueryKey,
2121
TPageParam = unknown,
22-
> extends QueryObserverExtendedOptions<
23-
TQueryFnData,
24-
TError,
25-
TData,
26-
InfiniteData<TQueryData, TPageParam>,
27-
TQueryKey,
28-
TPageParam
29-
>,
30-
InfiniteQueryPageParamsOptions<TQueryFnData, TPageParam> {}
22+
> = Overwrite<
23+
InfiniteQueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey, TPageParam>,
24+
QueryDataAdditionalOptions<
25+
TQueryFnData,
26+
TError,
27+
InfiniteData<TQueryData, TPageParam>,
28+
TQueryKey
29+
>
30+
>;
3131

3232
export type InfiniteQueryDataSource<TParams, TRequest, TResponse, TData, TError> = DataSource<
3333
QueryDataSourceContext,

0 commit comments

Comments
 (0)