floppy-disk 2.4.0-beta.1 → 2.4.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/preact/create-query.d.ts +9 -0
- package/esm/preact/create-query.js +47 -27
- package/esm/react/create-query.d.ts +9 -0
- package/esm/react/create-query.js +47 -27
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.js +6 -0
- package/lib/preact/create-query.d.ts +9 -0
- package/lib/preact/create-query.js +46 -26
- package/lib/react/create-query.d.ts +9 -0
- package/lib/react/create-query.js +46 -26
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +8 -1
- package/package.json +1 -1
|
@@ -178,6 +178,7 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
178
178
|
* This function should return a variable that will be used when fetching next page (`pageParam`).
|
|
179
179
|
*/
|
|
180
180
|
getNextPageParam?: (lastPage: TResponse, index: number) => any;
|
|
181
|
+
onBeforeFetch?: (cancel: () => void, state: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
181
182
|
onSuccess?: (response: TResponse, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
182
183
|
onError?: (error: TError, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
183
184
|
onSettled?: (stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
@@ -192,6 +193,14 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
192
193
|
* Defaults to `5 * 60 * 1000` (5 minutes).
|
|
193
194
|
*/
|
|
194
195
|
cacheTime?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Polling interval in milliseconds.
|
|
198
|
+
*
|
|
199
|
+
* Disabled by default.
|
|
200
|
+
*
|
|
201
|
+
* If the query is on error state, the polling interval will be disabled, and it will use `retry` instead.
|
|
202
|
+
*/
|
|
203
|
+
refetchInterval?: number | false | ((state: QueryState<TKey, TResponse, TData, TError>) => number | false);
|
|
195
204
|
};
|
|
196
205
|
export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = UseStores<TKey, QueryState<TKey, TResponse, TData, TError>> & {
|
|
197
206
|
/**
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { h as createElement } from 'preact';
|
|
2
2
|
import { useState } from 'preact/hooks';
|
|
3
|
-
import { hasValue, identityFn, noop } from '../utils';
|
|
3
|
+
import { getValueOrComputedValue, hasValue, identityFn, noop } from '../utils';
|
|
4
4
|
import { createStores } from './create-stores';
|
|
5
|
-
const getDecision = (value, param, { ifTrue, ifAlways }) => {
|
|
6
|
-
if (value === true || (typeof value === 'function' && value(param) === true)) {
|
|
7
|
-
ifTrue();
|
|
8
|
-
}
|
|
9
|
-
else if (value === 'always' || (typeof value === 'function' && value(param) === 'always')) {
|
|
10
|
-
ifAlways();
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
5
|
const INITIAL_QUERY_STATE = {
|
|
14
6
|
isWaiting: false,
|
|
15
7
|
isWaitingNextPage: false,
|
|
@@ -44,27 +36,36 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
44
36
|
const defaultFetchOnWindowFocus = options.fetchOnMount ?? true;
|
|
45
37
|
const { onFirstSubscribe = noop, onSubscribe = noop, onLastUnsubscribe = noop, onBeforeChangeKey = noop, defaultDeps = useQueryDefaultDeps, select = identityFn, staleTime = 3000, // 3 seconds
|
|
46
38
|
fetchOnMount = true, fetchOnWindowFocus = defaultFetchOnWindowFocus, enabled = true, retry = 1, retryDelay = 2000, // 2 seconds
|
|
47
|
-
keepPreviousData, getNextPageParam = () => undefined, onSuccess = noop, onError = noop, onSettled = noop, cacheTime = 5 * 60 * 1000, ...createStoresOptions } = options;
|
|
39
|
+
keepPreviousData, getNextPageParam = () => undefined, onBeforeFetch = noop, onSuccess = noop, onError = noop, onSettled = noop, cacheTime = 5 * 60 * 1000, refetchInterval = false, ...createStoresOptions } = options;
|
|
48
40
|
const retryTimeoutId = new Map();
|
|
49
41
|
const retryNextPageTimeoutId = new Map();
|
|
50
42
|
const resetTimeoutId = new Map();
|
|
43
|
+
const refetchIntervalTimeoutId = new Map();
|
|
51
44
|
const preventReplaceResponse = new Map(); // Prevent optimistic data to be replaced
|
|
52
45
|
const useQuery = createStores(({ get, set, key: _key, keyHash }) => {
|
|
53
46
|
const key = _key;
|
|
54
47
|
const getRetryProps = (error, retryCount) => {
|
|
55
48
|
const prevState = get();
|
|
56
|
-
const maxRetryCount = (
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
return { shouldRetry, delay };
|
|
49
|
+
const maxRetryCount = getValueOrComputedValue(retry, error, prevState) || 0;
|
|
50
|
+
const delay = getValueOrComputedValue(retryDelay, error, prevState) || 0;
|
|
51
|
+
return { shouldRetry: retryCount < maxRetryCount, delay };
|
|
60
52
|
};
|
|
61
53
|
const forceFetch = () => new Promise((resolve) => {
|
|
62
54
|
const responseAllPages = [];
|
|
63
55
|
const newPageParams = [undefined];
|
|
64
56
|
let pageParam = undefined;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
clearTimeout(refetchIntervalTimeoutId.get(keyHash));
|
|
58
|
+
const state = get();
|
|
59
|
+
const { isWaiting, isLoading, pageParams } = state;
|
|
60
|
+
if (isWaiting || !getValueOrComputedValue(enabled, key))
|
|
61
|
+
return resolve(state);
|
|
62
|
+
let shouldcancel = false;
|
|
63
|
+
const cancel = () => {
|
|
64
|
+
shouldcancel = true;
|
|
65
|
+
};
|
|
66
|
+
onBeforeFetch(cancel, state);
|
|
67
|
+
if (shouldcancel)
|
|
68
|
+
return resolve(state);
|
|
68
69
|
if (isLoading)
|
|
69
70
|
set({ isWaiting: true });
|
|
70
71
|
else
|
|
@@ -93,7 +94,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
93
94
|
callQuery();
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
const nextState = {
|
|
97
98
|
isWaiting: false,
|
|
98
99
|
status: 'success',
|
|
99
100
|
isLoading: false,
|
|
@@ -114,7 +115,15 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
114
115
|
pageParam: newPageParam,
|
|
115
116
|
pageParams: newPageParams,
|
|
116
117
|
hasNextPage: hasValue(newPageParam),
|
|
117
|
-
}
|
|
118
|
+
};
|
|
119
|
+
const refetchIntervalValue = typeof window !== 'undefined' &&
|
|
120
|
+
getValueOrComputedValue(refetchInterval, { ...get(), ...nextState });
|
|
121
|
+
if (refetchIntervalValue) {
|
|
122
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
123
|
+
forceFetch();
|
|
124
|
+
}, refetchIntervalValue));
|
|
125
|
+
}
|
|
126
|
+
set(nextState);
|
|
118
127
|
onSuccess(response, stateBeforeCallQuery);
|
|
119
128
|
resolve(get());
|
|
120
129
|
})
|
|
@@ -228,16 +237,25 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
228
237
|
}, (() => {
|
|
229
238
|
const fetchWindowFocusHandler = () => {
|
|
230
239
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
const result = getValueOrComputedValue(fetchOnWindowFocus, state.key);
|
|
241
|
+
if (result === 'always')
|
|
242
|
+
state.forceFetch();
|
|
243
|
+
else if (result)
|
|
244
|
+
state.fetch();
|
|
235
245
|
});
|
|
236
246
|
};
|
|
237
247
|
return {
|
|
238
248
|
...createStoresOptions,
|
|
239
249
|
defaultDeps,
|
|
240
250
|
onFirstSubscribe: (state) => {
|
|
251
|
+
if (state.isSuccess) {
|
|
252
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval, state);
|
|
253
|
+
if (refetchIntervalValue) {
|
|
254
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
255
|
+
state.forceFetch();
|
|
256
|
+
}, refetchIntervalValue));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
241
259
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
242
260
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
243
261
|
}
|
|
@@ -245,10 +263,11 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
245
263
|
onFirstSubscribe(state);
|
|
246
264
|
},
|
|
247
265
|
onSubscribe: (state) => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
266
|
+
const result = getValueOrComputedValue(fetchOnMount, state.key);
|
|
267
|
+
if (result === 'always')
|
|
268
|
+
state.forceFetch();
|
|
269
|
+
else if (result)
|
|
270
|
+
state.fetch();
|
|
252
271
|
onSubscribe(state);
|
|
253
272
|
},
|
|
254
273
|
onLastUnsubscribe: (state) => {
|
|
@@ -258,6 +277,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
258
277
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
259
278
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
260
279
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
280
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
261
281
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
262
282
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
263
283
|
useQuery.set(state.key, INITIAL_QUERY_STATE);
|
|
@@ -177,6 +177,7 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
177
177
|
* This function should return a variable that will be used when fetching next page (`pageParam`).
|
|
178
178
|
*/
|
|
179
179
|
getNextPageParam?: (lastPage: TResponse, index: number) => any;
|
|
180
|
+
onBeforeFetch?: (cancel: () => void, state: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
180
181
|
onSuccess?: (response: TResponse, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
181
182
|
onError?: (error: TError, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
182
183
|
onSettled?: (stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
@@ -191,6 +192,14 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
191
192
|
* Defaults to `5 * 60 * 1000` (5 minutes).
|
|
192
193
|
*/
|
|
193
194
|
cacheTime?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Polling interval in milliseconds.
|
|
197
|
+
*
|
|
198
|
+
* Disabled by default.
|
|
199
|
+
*
|
|
200
|
+
* If the query is on error state, the polling interval will be disabled, and it will use `retry` instead.
|
|
201
|
+
*/
|
|
202
|
+
refetchInterval?: number | false | ((state: QueryState<TKey, TResponse, TData, TError>) => number | false);
|
|
194
203
|
};
|
|
195
204
|
export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = UseStores<TKey, QueryState<TKey, TResponse, TData, TError>> & {
|
|
196
205
|
/**
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { createElement, useState } from 'react';
|
|
2
|
-
import { hasValue, identityFn, noop } from '../utils';
|
|
2
|
+
import { getValueOrComputedValue, hasValue, identityFn, noop } from '../utils';
|
|
3
3
|
import { createStores } from './create-stores';
|
|
4
|
-
const getDecision = (value, param, { ifTrue, ifAlways }) => {
|
|
5
|
-
if (value === true || (typeof value === 'function' && value(param) === true)) {
|
|
6
|
-
ifTrue();
|
|
7
|
-
}
|
|
8
|
-
else if (value === 'always' || (typeof value === 'function' && value(param) === 'always')) {
|
|
9
|
-
ifAlways();
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
4
|
const INITIAL_QUERY_STATE = {
|
|
13
5
|
isWaiting: false,
|
|
14
6
|
isWaitingNextPage: false,
|
|
@@ -43,27 +35,36 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
43
35
|
const defaultFetchOnWindowFocus = options.fetchOnMount ?? true;
|
|
44
36
|
const { onFirstSubscribe = noop, onSubscribe = noop, onLastUnsubscribe = noop, onBeforeChangeKey = noop, defaultDeps = useQueryDefaultDeps, select = identityFn, staleTime = 3000, // 3 seconds
|
|
45
37
|
fetchOnMount = true, fetchOnWindowFocus = defaultFetchOnWindowFocus, enabled = true, retry = 1, retryDelay = 2000, // 2 seconds
|
|
46
|
-
keepPreviousData, getNextPageParam = () => undefined, onSuccess = noop, onError = noop, onSettled = noop, cacheTime = 5 * 60 * 1000, ...createStoresOptions } = options;
|
|
38
|
+
keepPreviousData, getNextPageParam = () => undefined, onBeforeFetch = noop, onSuccess = noop, onError = noop, onSettled = noop, cacheTime = 5 * 60 * 1000, refetchInterval = false, ...createStoresOptions } = options;
|
|
47
39
|
const retryTimeoutId = new Map();
|
|
48
40
|
const retryNextPageTimeoutId = new Map();
|
|
49
41
|
const resetTimeoutId = new Map();
|
|
42
|
+
const refetchIntervalTimeoutId = new Map();
|
|
50
43
|
const preventReplaceResponse = new Map(); // Prevent optimistic data to be replaced
|
|
51
44
|
const useQuery = createStores(({ get, set, key: _key, keyHash }) => {
|
|
52
45
|
const key = _key;
|
|
53
46
|
const getRetryProps = (error, retryCount) => {
|
|
54
47
|
const prevState = get();
|
|
55
|
-
const maxRetryCount = (
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
return { shouldRetry, delay };
|
|
48
|
+
const maxRetryCount = getValueOrComputedValue(retry, error, prevState) || 0;
|
|
49
|
+
const delay = getValueOrComputedValue(retryDelay, error, prevState) || 0;
|
|
50
|
+
return { shouldRetry: retryCount < maxRetryCount, delay };
|
|
59
51
|
};
|
|
60
52
|
const forceFetch = () => new Promise((resolve) => {
|
|
61
53
|
const responseAllPages = [];
|
|
62
54
|
const newPageParams = [undefined];
|
|
63
55
|
let pageParam = undefined;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
clearTimeout(refetchIntervalTimeoutId.get(keyHash));
|
|
57
|
+
const state = get();
|
|
58
|
+
const { isWaiting, isLoading, pageParams } = state;
|
|
59
|
+
if (isWaiting || !getValueOrComputedValue(enabled, key))
|
|
60
|
+
return resolve(state);
|
|
61
|
+
let shouldcancel = false;
|
|
62
|
+
const cancel = () => {
|
|
63
|
+
shouldcancel = true;
|
|
64
|
+
};
|
|
65
|
+
onBeforeFetch(cancel, state);
|
|
66
|
+
if (shouldcancel)
|
|
67
|
+
return resolve(state);
|
|
67
68
|
if (isLoading)
|
|
68
69
|
set({ isWaiting: true });
|
|
69
70
|
else
|
|
@@ -92,7 +93,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
92
93
|
callQuery();
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
+
const nextState = {
|
|
96
97
|
isWaiting: false,
|
|
97
98
|
status: 'success',
|
|
98
99
|
isLoading: false,
|
|
@@ -113,7 +114,15 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
113
114
|
pageParam: newPageParam,
|
|
114
115
|
pageParams: newPageParams,
|
|
115
116
|
hasNextPage: hasValue(newPageParam),
|
|
116
|
-
}
|
|
117
|
+
};
|
|
118
|
+
const refetchIntervalValue = typeof window !== 'undefined' &&
|
|
119
|
+
getValueOrComputedValue(refetchInterval, { ...get(), ...nextState });
|
|
120
|
+
if (refetchIntervalValue) {
|
|
121
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
122
|
+
forceFetch();
|
|
123
|
+
}, refetchIntervalValue));
|
|
124
|
+
}
|
|
125
|
+
set(nextState);
|
|
117
126
|
onSuccess(response, stateBeforeCallQuery);
|
|
118
127
|
resolve(get());
|
|
119
128
|
})
|
|
@@ -227,16 +236,25 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
227
236
|
}, (() => {
|
|
228
237
|
const fetchWindowFocusHandler = () => {
|
|
229
238
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
239
|
+
const result = getValueOrComputedValue(fetchOnWindowFocus, state.key);
|
|
240
|
+
if (result === 'always')
|
|
241
|
+
state.forceFetch();
|
|
242
|
+
else if (result)
|
|
243
|
+
state.fetch();
|
|
234
244
|
});
|
|
235
245
|
};
|
|
236
246
|
return {
|
|
237
247
|
...createStoresOptions,
|
|
238
248
|
defaultDeps,
|
|
239
249
|
onFirstSubscribe: (state) => {
|
|
250
|
+
if (state.isSuccess) {
|
|
251
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval, state);
|
|
252
|
+
if (refetchIntervalValue) {
|
|
253
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
254
|
+
state.forceFetch();
|
|
255
|
+
}, refetchIntervalValue));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
240
258
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
241
259
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
242
260
|
}
|
|
@@ -244,10 +262,11 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
244
262
|
onFirstSubscribe(state);
|
|
245
263
|
},
|
|
246
264
|
onSubscribe: (state) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
265
|
+
const result = getValueOrComputedValue(fetchOnMount, state.key);
|
|
266
|
+
if (result === 'always')
|
|
267
|
+
state.forceFetch();
|
|
268
|
+
else if (result)
|
|
269
|
+
state.fetch();
|
|
251
270
|
onSubscribe(state);
|
|
252
271
|
},
|
|
253
272
|
onLastUnsubscribe: (state) => {
|
|
@@ -257,6 +276,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
257
276
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
258
277
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
259
278
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
279
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
260
280
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
261
281
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
262
282
|
useQuery.set(state.key, INITIAL_QUERY_STATE);
|
package/esm/utils/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export declare const noop: () => void;
|
|
|
2
2
|
export declare const identityFn: <T>(value: T) => T;
|
|
3
3
|
export declare const hasValue: (value: any) => boolean;
|
|
4
4
|
export declare const hashStoreKey: (obj?: any) => string;
|
|
5
|
+
export declare const getValueOrComputedValue: <T, P extends any[]>(valueOrComputeValueFn: T | ((...params: P) => T), ...params: P) => T;
|
package/esm/utils/index.js
CHANGED
|
@@ -2,3 +2,9 @@ export const noop = () => { };
|
|
|
2
2
|
export const identityFn = (value) => value;
|
|
3
3
|
export const hasValue = (value) => value !== undefined && value !== null;
|
|
4
4
|
export const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
|
|
5
|
+
export const getValueOrComputedValue = (valueOrComputeValueFn, ...params) => {
|
|
6
|
+
if (typeof valueOrComputeValueFn === 'function') {
|
|
7
|
+
return valueOrComputeValueFn(...params);
|
|
8
|
+
}
|
|
9
|
+
return valueOrComputeValueFn;
|
|
10
|
+
};
|
|
@@ -178,6 +178,7 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
178
178
|
* This function should return a variable that will be used when fetching next page (`pageParam`).
|
|
179
179
|
*/
|
|
180
180
|
getNextPageParam?: (lastPage: TResponse, index: number) => any;
|
|
181
|
+
onBeforeFetch?: (cancel: () => void, state: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
181
182
|
onSuccess?: (response: TResponse, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
182
183
|
onError?: (error: TError, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
183
184
|
onSettled?: (stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
@@ -192,6 +193,14 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
192
193
|
* Defaults to `5 * 60 * 1000` (5 minutes).
|
|
193
194
|
*/
|
|
194
195
|
cacheTime?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Polling interval in milliseconds.
|
|
198
|
+
*
|
|
199
|
+
* Disabled by default.
|
|
200
|
+
*
|
|
201
|
+
* If the query is on error state, the polling interval will be disabled, and it will use `retry` instead.
|
|
202
|
+
*/
|
|
203
|
+
refetchInterval?: number | false | ((state: QueryState<TKey, TResponse, TData, TError>) => number | false);
|
|
195
204
|
};
|
|
196
205
|
export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = UseStores<TKey, QueryState<TKey, TResponse, TData, TError>> & {
|
|
197
206
|
/**
|
|
@@ -5,14 +5,6 @@ const preact_1 = require("preact");
|
|
|
5
5
|
const hooks_1 = require("preact/hooks");
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const create_stores_1 = require("./create-stores");
|
|
8
|
-
const getDecision = (value, param, { ifTrue, ifAlways }) => {
|
|
9
|
-
if (value === true || (typeof value === 'function' && value(param) === true)) {
|
|
10
|
-
ifTrue();
|
|
11
|
-
}
|
|
12
|
-
else if (value === 'always' || (typeof value === 'function' && value(param) === 'always')) {
|
|
13
|
-
ifAlways();
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
8
|
const INITIAL_QUERY_STATE = {
|
|
17
9
|
isWaiting: false,
|
|
18
10
|
isWaitingNextPage: false,
|
|
@@ -47,27 +39,36 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
47
39
|
const defaultFetchOnWindowFocus = options.fetchOnMount ?? true;
|
|
48
40
|
const { onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, onBeforeChangeKey = utils_1.noop, defaultDeps = useQueryDefaultDeps, select = utils_1.identityFn, staleTime = 3000, // 3 seconds
|
|
49
41
|
fetchOnMount = true, fetchOnWindowFocus = defaultFetchOnWindowFocus, enabled = true, retry = 1, retryDelay = 2000, // 2 seconds
|
|
50
|
-
keepPreviousData, getNextPageParam = () => undefined, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, cacheTime = 5 * 60 * 1000, ...createStoresOptions } = options;
|
|
42
|
+
keepPreviousData, getNextPageParam = () => undefined, onBeforeFetch = utils_1.noop, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, cacheTime = 5 * 60 * 1000, refetchInterval = false, ...createStoresOptions } = options;
|
|
51
43
|
const retryTimeoutId = new Map();
|
|
52
44
|
const retryNextPageTimeoutId = new Map();
|
|
53
45
|
const resetTimeoutId = new Map();
|
|
46
|
+
const refetchIntervalTimeoutId = new Map();
|
|
54
47
|
const preventReplaceResponse = new Map(); // Prevent optimistic data to be replaced
|
|
55
48
|
const useQuery = (0, create_stores_1.createStores)(({ get, set, key: _key, keyHash }) => {
|
|
56
49
|
const key = _key;
|
|
57
50
|
const getRetryProps = (error, retryCount) => {
|
|
58
51
|
const prevState = get();
|
|
59
|
-
const maxRetryCount = (
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
return { shouldRetry, delay };
|
|
52
|
+
const maxRetryCount = (0, utils_1.getValueOrComputedValue)(retry, error, prevState) || 0;
|
|
53
|
+
const delay = (0, utils_1.getValueOrComputedValue)(retryDelay, error, prevState) || 0;
|
|
54
|
+
return { shouldRetry: retryCount < maxRetryCount, delay };
|
|
63
55
|
};
|
|
64
56
|
const forceFetch = () => new Promise((resolve) => {
|
|
65
57
|
const responseAllPages = [];
|
|
66
58
|
const newPageParams = [undefined];
|
|
67
59
|
let pageParam = undefined;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
clearTimeout(refetchIntervalTimeoutId.get(keyHash));
|
|
61
|
+
const state = get();
|
|
62
|
+
const { isWaiting, isLoading, pageParams } = state;
|
|
63
|
+
if (isWaiting || !(0, utils_1.getValueOrComputedValue)(enabled, key))
|
|
64
|
+
return resolve(state);
|
|
65
|
+
let shouldcancel = false;
|
|
66
|
+
const cancel = () => {
|
|
67
|
+
shouldcancel = true;
|
|
68
|
+
};
|
|
69
|
+
onBeforeFetch(cancel, state);
|
|
70
|
+
if (shouldcancel)
|
|
71
|
+
return resolve(state);
|
|
71
72
|
if (isLoading)
|
|
72
73
|
set({ isWaiting: true });
|
|
73
74
|
else
|
|
@@ -96,7 +97,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
96
97
|
callQuery();
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
+
const nextState = {
|
|
100
101
|
isWaiting: false,
|
|
101
102
|
status: 'success',
|
|
102
103
|
isLoading: false,
|
|
@@ -117,7 +118,15 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
117
118
|
pageParam: newPageParam,
|
|
118
119
|
pageParams: newPageParams,
|
|
119
120
|
hasNextPage: (0, utils_1.hasValue)(newPageParam),
|
|
120
|
-
}
|
|
121
|
+
};
|
|
122
|
+
const refetchIntervalValue = typeof window !== 'undefined' &&
|
|
123
|
+
(0, utils_1.getValueOrComputedValue)(refetchInterval, { ...get(), ...nextState });
|
|
124
|
+
if (refetchIntervalValue) {
|
|
125
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
126
|
+
forceFetch();
|
|
127
|
+
}, refetchIntervalValue));
|
|
128
|
+
}
|
|
129
|
+
set(nextState);
|
|
121
130
|
onSuccess(response, stateBeforeCallQuery);
|
|
122
131
|
resolve(get());
|
|
123
132
|
})
|
|
@@ -231,16 +240,25 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
231
240
|
}, (() => {
|
|
232
241
|
const fetchWindowFocusHandler = () => {
|
|
233
242
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
243
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnWindowFocus, state.key);
|
|
244
|
+
if (result === 'always')
|
|
245
|
+
state.forceFetch();
|
|
246
|
+
else if (result)
|
|
247
|
+
state.fetch();
|
|
238
248
|
});
|
|
239
249
|
};
|
|
240
250
|
return {
|
|
241
251
|
...createStoresOptions,
|
|
242
252
|
defaultDeps,
|
|
243
253
|
onFirstSubscribe: (state) => {
|
|
254
|
+
if (state.isSuccess) {
|
|
255
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval, state);
|
|
256
|
+
if (refetchIntervalValue) {
|
|
257
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
258
|
+
state.forceFetch();
|
|
259
|
+
}, refetchIntervalValue));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
244
262
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
245
263
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
246
264
|
}
|
|
@@ -248,10 +266,11 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
248
266
|
onFirstSubscribe(state);
|
|
249
267
|
},
|
|
250
268
|
onSubscribe: (state) => {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
269
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnMount, state.key);
|
|
270
|
+
if (result === 'always')
|
|
271
|
+
state.forceFetch();
|
|
272
|
+
else if (result)
|
|
273
|
+
state.fetch();
|
|
255
274
|
onSubscribe(state);
|
|
256
275
|
},
|
|
257
276
|
onLastUnsubscribe: (state) => {
|
|
@@ -261,6 +280,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
261
280
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
262
281
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
263
282
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
283
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
264
284
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
265
285
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
266
286
|
useQuery.set(state.key, INITIAL_QUERY_STATE);
|
|
@@ -177,6 +177,7 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
177
177
|
* This function should return a variable that will be used when fetching next page (`pageParam`).
|
|
178
178
|
*/
|
|
179
179
|
getNextPageParam?: (lastPage: TResponse, index: number) => any;
|
|
180
|
+
onBeforeFetch?: (cancel: () => void, state: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
180
181
|
onSuccess?: (response: TResponse, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
181
182
|
onError?: (error: TError, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
182
183
|
onSettled?: (stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError>) => void;
|
|
@@ -191,6 +192,14 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
|
|
|
191
192
|
* Defaults to `5 * 60 * 1000` (5 minutes).
|
|
192
193
|
*/
|
|
193
194
|
cacheTime?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Polling interval in milliseconds.
|
|
197
|
+
*
|
|
198
|
+
* Disabled by default.
|
|
199
|
+
*
|
|
200
|
+
* If the query is on error state, the polling interval will be disabled, and it will use `retry` instead.
|
|
201
|
+
*/
|
|
202
|
+
refetchInterval?: number | false | ((state: QueryState<TKey, TResponse, TData, TError>) => number | false);
|
|
194
203
|
};
|
|
195
204
|
export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = UseStores<TKey, QueryState<TKey, TResponse, TData, TError>> & {
|
|
196
205
|
/**
|
|
@@ -4,14 +4,6 @@ exports.createQuery = void 0;
|
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const create_stores_1 = require("./create-stores");
|
|
7
|
-
const getDecision = (value, param, { ifTrue, ifAlways }) => {
|
|
8
|
-
if (value === true || (typeof value === 'function' && value(param) === true)) {
|
|
9
|
-
ifTrue();
|
|
10
|
-
}
|
|
11
|
-
else if (value === 'always' || (typeof value === 'function' && value(param) === 'always')) {
|
|
12
|
-
ifAlways();
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
7
|
const INITIAL_QUERY_STATE = {
|
|
16
8
|
isWaiting: false,
|
|
17
9
|
isWaitingNextPage: false,
|
|
@@ -46,27 +38,36 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
46
38
|
const defaultFetchOnWindowFocus = options.fetchOnMount ?? true;
|
|
47
39
|
const { onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, onBeforeChangeKey = utils_1.noop, defaultDeps = useQueryDefaultDeps, select = utils_1.identityFn, staleTime = 3000, // 3 seconds
|
|
48
40
|
fetchOnMount = true, fetchOnWindowFocus = defaultFetchOnWindowFocus, enabled = true, retry = 1, retryDelay = 2000, // 2 seconds
|
|
49
|
-
keepPreviousData, getNextPageParam = () => undefined, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, cacheTime = 5 * 60 * 1000, ...createStoresOptions } = options;
|
|
41
|
+
keepPreviousData, getNextPageParam = () => undefined, onBeforeFetch = utils_1.noop, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, cacheTime = 5 * 60 * 1000, refetchInterval = false, ...createStoresOptions } = options;
|
|
50
42
|
const retryTimeoutId = new Map();
|
|
51
43
|
const retryNextPageTimeoutId = new Map();
|
|
52
44
|
const resetTimeoutId = new Map();
|
|
45
|
+
const refetchIntervalTimeoutId = new Map();
|
|
53
46
|
const preventReplaceResponse = new Map(); // Prevent optimistic data to be replaced
|
|
54
47
|
const useQuery = (0, create_stores_1.createStores)(({ get, set, key: _key, keyHash }) => {
|
|
55
48
|
const key = _key;
|
|
56
49
|
const getRetryProps = (error, retryCount) => {
|
|
57
50
|
const prevState = get();
|
|
58
|
-
const maxRetryCount = (
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
return { shouldRetry, delay };
|
|
51
|
+
const maxRetryCount = (0, utils_1.getValueOrComputedValue)(retry, error, prevState) || 0;
|
|
52
|
+
const delay = (0, utils_1.getValueOrComputedValue)(retryDelay, error, prevState) || 0;
|
|
53
|
+
return { shouldRetry: retryCount < maxRetryCount, delay };
|
|
62
54
|
};
|
|
63
55
|
const forceFetch = () => new Promise((resolve) => {
|
|
64
56
|
const responseAllPages = [];
|
|
65
57
|
const newPageParams = [undefined];
|
|
66
58
|
let pageParam = undefined;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
clearTimeout(refetchIntervalTimeoutId.get(keyHash));
|
|
60
|
+
const state = get();
|
|
61
|
+
const { isWaiting, isLoading, pageParams } = state;
|
|
62
|
+
if (isWaiting || !(0, utils_1.getValueOrComputedValue)(enabled, key))
|
|
63
|
+
return resolve(state);
|
|
64
|
+
let shouldcancel = false;
|
|
65
|
+
const cancel = () => {
|
|
66
|
+
shouldcancel = true;
|
|
67
|
+
};
|
|
68
|
+
onBeforeFetch(cancel, state);
|
|
69
|
+
if (shouldcancel)
|
|
70
|
+
return resolve(state);
|
|
70
71
|
if (isLoading)
|
|
71
72
|
set({ isWaiting: true });
|
|
72
73
|
else
|
|
@@ -95,7 +96,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
95
96
|
callQuery();
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
const nextState = {
|
|
99
100
|
isWaiting: false,
|
|
100
101
|
status: 'success',
|
|
101
102
|
isLoading: false,
|
|
@@ -116,7 +117,15 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
116
117
|
pageParam: newPageParam,
|
|
117
118
|
pageParams: newPageParams,
|
|
118
119
|
hasNextPage: (0, utils_1.hasValue)(newPageParam),
|
|
119
|
-
}
|
|
120
|
+
};
|
|
121
|
+
const refetchIntervalValue = typeof window !== 'undefined' &&
|
|
122
|
+
(0, utils_1.getValueOrComputedValue)(refetchInterval, { ...get(), ...nextState });
|
|
123
|
+
if (refetchIntervalValue) {
|
|
124
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
125
|
+
forceFetch();
|
|
126
|
+
}, refetchIntervalValue));
|
|
127
|
+
}
|
|
128
|
+
set(nextState);
|
|
120
129
|
onSuccess(response, stateBeforeCallQuery);
|
|
121
130
|
resolve(get());
|
|
122
131
|
})
|
|
@@ -230,16 +239,25 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
230
239
|
}, (() => {
|
|
231
240
|
const fetchWindowFocusHandler = () => {
|
|
232
241
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
242
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnWindowFocus, state.key);
|
|
243
|
+
if (result === 'always')
|
|
244
|
+
state.forceFetch();
|
|
245
|
+
else if (result)
|
|
246
|
+
state.fetch();
|
|
237
247
|
});
|
|
238
248
|
};
|
|
239
249
|
return {
|
|
240
250
|
...createStoresOptions,
|
|
241
251
|
defaultDeps,
|
|
242
252
|
onFirstSubscribe: (state) => {
|
|
253
|
+
if (state.isSuccess) {
|
|
254
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval, state);
|
|
255
|
+
if (refetchIntervalValue) {
|
|
256
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
257
|
+
state.forceFetch();
|
|
258
|
+
}, refetchIntervalValue));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
243
261
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
244
262
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
245
263
|
}
|
|
@@ -247,10 +265,11 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
247
265
|
onFirstSubscribe(state);
|
|
248
266
|
},
|
|
249
267
|
onSubscribe: (state) => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
268
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnMount, state.key);
|
|
269
|
+
if (result === 'always')
|
|
270
|
+
state.forceFetch();
|
|
271
|
+
else if (result)
|
|
272
|
+
state.fetch();
|
|
254
273
|
onSubscribe(state);
|
|
255
274
|
},
|
|
256
275
|
onLastUnsubscribe: (state) => {
|
|
@@ -260,6 +279,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
260
279
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
261
280
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
262
281
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
282
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
263
283
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
264
284
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
265
285
|
useQuery.set(state.key, INITIAL_QUERY_STATE);
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export declare const noop: () => void;
|
|
|
2
2
|
export declare const identityFn: <T>(value: T) => T;
|
|
3
3
|
export declare const hasValue: (value: any) => boolean;
|
|
4
4
|
export declare const hashStoreKey: (obj?: any) => string;
|
|
5
|
+
export declare const getValueOrComputedValue: <T, P extends any[]>(valueOrComputeValueFn: T | ((...params: P) => T), ...params: P) => T;
|
package/lib/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hashStoreKey = exports.hasValue = exports.identityFn = exports.noop = void 0;
|
|
3
|
+
exports.getValueOrComputedValue = exports.hashStoreKey = exports.hasValue = exports.identityFn = exports.noop = void 0;
|
|
4
4
|
const noop = () => { };
|
|
5
5
|
exports.noop = noop;
|
|
6
6
|
const identityFn = (value) => value;
|
|
@@ -9,3 +9,10 @@ const hasValue = (value) => value !== undefined && value !== null;
|
|
|
9
9
|
exports.hasValue = hasValue;
|
|
10
10
|
const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
|
|
11
11
|
exports.hashStoreKey = hashStoreKey;
|
|
12
|
+
const getValueOrComputedValue = (valueOrComputeValueFn, ...params) => {
|
|
13
|
+
if (typeof valueOrComputeValueFn === 'function') {
|
|
14
|
+
return valueOrComputeValueFn(...params);
|
|
15
|
+
}
|
|
16
|
+
return valueOrComputeValueFn;
|
|
17
|
+
};
|
|
18
|
+
exports.getValueOrComputedValue = getValueOrComputedValue;
|