floppy-disk 2.4.0-beta.1 → 2.4.0-beta.2
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 +43 -25
- package/esm/react/create-query.d.ts +9 -0
- package/esm/react/create-query.js +43 -25
- 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 +42 -24
- package/lib/react/create-query.d.ts +9 -0
- package/lib/react/create-query.js +42 -24
- 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 | (() => 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
|
|
@@ -115,6 +116,12 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
115
116
|
pageParams: newPageParams,
|
|
116
117
|
hasNextPage: hasValue(newPageParam),
|
|
117
118
|
});
|
|
119
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval);
|
|
120
|
+
if (refetchIntervalValue) {
|
|
121
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
122
|
+
forceFetch();
|
|
123
|
+
}, refetchIntervalValue));
|
|
124
|
+
}
|
|
118
125
|
onSuccess(response, stateBeforeCallQuery);
|
|
119
126
|
resolve(get());
|
|
120
127
|
})
|
|
@@ -228,16 +235,25 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
228
235
|
}, (() => {
|
|
229
236
|
const fetchWindowFocusHandler = () => {
|
|
230
237
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
const result = getValueOrComputedValue(fetchOnWindowFocus, state.key);
|
|
239
|
+
if (result === 'always')
|
|
240
|
+
state.forceFetch();
|
|
241
|
+
else if (result)
|
|
242
|
+
state.fetch();
|
|
235
243
|
});
|
|
236
244
|
};
|
|
237
245
|
return {
|
|
238
246
|
...createStoresOptions,
|
|
239
247
|
defaultDeps,
|
|
240
248
|
onFirstSubscribe: (state) => {
|
|
249
|
+
if (state.isSuccess) {
|
|
250
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval);
|
|
251
|
+
if (refetchIntervalValue) {
|
|
252
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
253
|
+
state.forceFetch();
|
|
254
|
+
}, refetchIntervalValue));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
241
257
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
242
258
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
243
259
|
}
|
|
@@ -245,10 +261,11 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
245
261
|
onFirstSubscribe(state);
|
|
246
262
|
},
|
|
247
263
|
onSubscribe: (state) => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
264
|
+
const result = getValueOrComputedValue(fetchOnMount, state.key);
|
|
265
|
+
if (result === 'always')
|
|
266
|
+
state.forceFetch();
|
|
267
|
+
else if (result)
|
|
268
|
+
state.fetch();
|
|
252
269
|
onSubscribe(state);
|
|
253
270
|
},
|
|
254
271
|
onLastUnsubscribe: (state) => {
|
|
@@ -258,6 +275,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
258
275
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
259
276
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
260
277
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
278
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
261
279
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
262
280
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
263
281
|
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 | (() => 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
|
|
@@ -114,6 +115,12 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
114
115
|
pageParams: newPageParams,
|
|
115
116
|
hasNextPage: hasValue(newPageParam),
|
|
116
117
|
});
|
|
118
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval);
|
|
119
|
+
if (refetchIntervalValue) {
|
|
120
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
121
|
+
forceFetch();
|
|
122
|
+
}, refetchIntervalValue));
|
|
123
|
+
}
|
|
117
124
|
onSuccess(response, stateBeforeCallQuery);
|
|
118
125
|
resolve(get());
|
|
119
126
|
})
|
|
@@ -227,16 +234,25 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
227
234
|
}, (() => {
|
|
228
235
|
const fetchWindowFocusHandler = () => {
|
|
229
236
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
const result = getValueOrComputedValue(fetchOnWindowFocus, state.key);
|
|
238
|
+
if (result === 'always')
|
|
239
|
+
state.forceFetch();
|
|
240
|
+
else if (result)
|
|
241
|
+
state.fetch();
|
|
234
242
|
});
|
|
235
243
|
};
|
|
236
244
|
return {
|
|
237
245
|
...createStoresOptions,
|
|
238
246
|
defaultDeps,
|
|
239
247
|
onFirstSubscribe: (state) => {
|
|
248
|
+
if (state.isSuccess) {
|
|
249
|
+
const refetchIntervalValue = typeof window !== 'undefined' && getValueOrComputedValue(refetchInterval);
|
|
250
|
+
if (refetchIntervalValue) {
|
|
251
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
252
|
+
state.forceFetch();
|
|
253
|
+
}, refetchIntervalValue));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
240
256
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
241
257
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
242
258
|
}
|
|
@@ -244,10 +260,11 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
244
260
|
onFirstSubscribe(state);
|
|
245
261
|
},
|
|
246
262
|
onSubscribe: (state) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
263
|
+
const result = getValueOrComputedValue(fetchOnMount, state.key);
|
|
264
|
+
if (result === 'always')
|
|
265
|
+
state.forceFetch();
|
|
266
|
+
else if (result)
|
|
267
|
+
state.fetch();
|
|
251
268
|
onSubscribe(state);
|
|
252
269
|
},
|
|
253
270
|
onLastUnsubscribe: (state) => {
|
|
@@ -257,6 +274,7 @@ export const createQuery = (queryFn, options = {}) => {
|
|
|
257
274
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
258
275
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
259
276
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
277
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
260
278
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
261
279
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
262
280
|
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 | (() => 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
|
|
@@ -118,6 +119,12 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
118
119
|
pageParams: newPageParams,
|
|
119
120
|
hasNextPage: (0, utils_1.hasValue)(newPageParam),
|
|
120
121
|
});
|
|
122
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval);
|
|
123
|
+
if (refetchIntervalValue) {
|
|
124
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
125
|
+
forceFetch();
|
|
126
|
+
}, refetchIntervalValue));
|
|
127
|
+
}
|
|
121
128
|
onSuccess(response, stateBeforeCallQuery);
|
|
122
129
|
resolve(get());
|
|
123
130
|
})
|
|
@@ -231,16 +238,25 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
231
238
|
}, (() => {
|
|
232
239
|
const fetchWindowFocusHandler = () => {
|
|
233
240
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
241
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnWindowFocus, state.key);
|
|
242
|
+
if (result === 'always')
|
|
243
|
+
state.forceFetch();
|
|
244
|
+
else if (result)
|
|
245
|
+
state.fetch();
|
|
238
246
|
});
|
|
239
247
|
};
|
|
240
248
|
return {
|
|
241
249
|
...createStoresOptions,
|
|
242
250
|
defaultDeps,
|
|
243
251
|
onFirstSubscribe: (state) => {
|
|
252
|
+
if (state.isSuccess) {
|
|
253
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval);
|
|
254
|
+
if (refetchIntervalValue) {
|
|
255
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
256
|
+
state.forceFetch();
|
|
257
|
+
}, refetchIntervalValue));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
244
260
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
245
261
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
246
262
|
}
|
|
@@ -248,10 +264,11 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
248
264
|
onFirstSubscribe(state);
|
|
249
265
|
},
|
|
250
266
|
onSubscribe: (state) => {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
267
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnMount, state.key);
|
|
268
|
+
if (result === 'always')
|
|
269
|
+
state.forceFetch();
|
|
270
|
+
else if (result)
|
|
271
|
+
state.fetch();
|
|
255
272
|
onSubscribe(state);
|
|
256
273
|
},
|
|
257
274
|
onLastUnsubscribe: (state) => {
|
|
@@ -261,6 +278,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
261
278
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
262
279
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
263
280
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
281
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
264
282
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
265
283
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
266
284
|
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 | (() => 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
|
|
@@ -117,6 +118,12 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
117
118
|
pageParams: newPageParams,
|
|
118
119
|
hasNextPage: (0, utils_1.hasValue)(newPageParam),
|
|
119
120
|
});
|
|
121
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval);
|
|
122
|
+
if (refetchIntervalValue) {
|
|
123
|
+
refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
|
|
124
|
+
forceFetch();
|
|
125
|
+
}, refetchIntervalValue));
|
|
126
|
+
}
|
|
120
127
|
onSuccess(response, stateBeforeCallQuery);
|
|
121
128
|
resolve(get());
|
|
122
129
|
})
|
|
@@ -230,16 +237,25 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
230
237
|
}, (() => {
|
|
231
238
|
const fetchWindowFocusHandler = () => {
|
|
232
239
|
useQuery.getAllWithSubscriber().forEach((state) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
240
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnWindowFocus, state.key);
|
|
241
|
+
if (result === 'always')
|
|
242
|
+
state.forceFetch();
|
|
243
|
+
else if (result)
|
|
244
|
+
state.fetch();
|
|
237
245
|
});
|
|
238
246
|
};
|
|
239
247
|
return {
|
|
240
248
|
...createStoresOptions,
|
|
241
249
|
defaultDeps,
|
|
242
250
|
onFirstSubscribe: (state) => {
|
|
251
|
+
if (state.isSuccess) {
|
|
252
|
+
const refetchIntervalValue = typeof window !== 'undefined' && (0, utils_1.getValueOrComputedValue)(refetchInterval);
|
|
253
|
+
if (refetchIntervalValue) {
|
|
254
|
+
refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
255
|
+
state.forceFetch();
|
|
256
|
+
}, refetchIntervalValue));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
243
259
|
if (typeof window !== 'undefined' && fetchOnWindowFocus) {
|
|
244
260
|
window.addEventListener('focus', fetchWindowFocusHandler);
|
|
245
261
|
}
|
|
@@ -247,10 +263,11 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
247
263
|
onFirstSubscribe(state);
|
|
248
264
|
},
|
|
249
265
|
onSubscribe: (state) => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
266
|
+
const result = (0, utils_1.getValueOrComputedValue)(fetchOnMount, state.key);
|
|
267
|
+
if (result === 'always')
|
|
268
|
+
state.forceFetch();
|
|
269
|
+
else if (result)
|
|
270
|
+
state.fetch();
|
|
254
271
|
onSubscribe(state);
|
|
255
272
|
},
|
|
256
273
|
onLastUnsubscribe: (state) => {
|
|
@@ -260,6 +277,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
260
277
|
useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
|
|
261
278
|
clearTimeout(retryTimeoutId.get(state.keyHash));
|
|
262
279
|
clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
|
|
280
|
+
clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
|
|
263
281
|
if (typeof window !== 'undefined' && cacheTime !== Infinity) {
|
|
264
282
|
resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
|
|
265
283
|
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;
|