floppy-disk 2.4.0 → 2.5.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/README.md CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  useInfiniteQuery,
19
19
  useMutation,
20
20
  } from '@tanstack/react-query'; // 41 kB (gzipped: 11 kB)
21
- import { createQuery, createMutation } from 'floppy-disk'; // 8.4 kB (gzipped: 2.8 kB) 🎉
21
+ import { createQuery, createMutation } from 'floppy-disk'; // 9.2 kB (gzipped: 3.1 kB) 🎉
22
22
  ```
23
23
 
24
24
  - Using Zustand & React-Query: https://demo-zustand-react-query.vercel.app/
@@ -641,7 +641,7 @@ const usePokemonsInfQuery = createQuery(
641
641
  throw res;
642
642
  },
643
643
  {
644
- select: (response, { data }) => [...(data || []), ...response.results],
644
+ select: (response, { data = [] }) => [...data, ...response.results],
645
645
  getNextPageParam: (lastPageResponse, i) => {
646
646
  if (i > 5) return undefined; // Return undefined means you have reached the end of the pages
647
647
  return i * 10;
@@ -650,11 +650,11 @@ const usePokemonsInfQuery = createQuery(
650
650
  );
651
651
 
652
652
  function PokemonListPage() {
653
- const { data, fetchNextPage, hasNextPage, isWaitingNextPage } = usePokemonsInfQuery();
653
+ const { data = [], fetchNextPage, hasNextPage, isWaitingNextPage } = usePokemonsInfQuery();
654
654
 
655
655
  return (
656
656
  <div>
657
- {data?.map((pokemon) => (
657
+ {data.map((pokemon) => (
658
658
  <div key={pokemon.name}>{pokemon.name}</div>
659
659
  ))}
660
660
  {isWaitingNextPage ? (
@@ -7,9 +7,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
7
7
  isWaiting: boolean;
8
8
  isSuccess: boolean;
9
9
  isError: boolean;
10
- response: TResponse | null;
10
+ response: TResponse | undefined;
11
11
  responseUpdatedAt: number | null;
12
- error: TError | null;
12
+ error: TError | undefined;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
15
  * Mutate function.
@@ -9,9 +9,9 @@ export const createMutation = (mutationFn, options = {}) => {
9
9
  isWaiting: false,
10
10
  isSuccess: false,
11
11
  isError: false,
12
- response: null,
12
+ response: undefined,
13
13
  responseUpdatedAt: null,
14
- error: null,
14
+ error: undefined,
15
15
  errorUpdatedAt: null,
16
16
  mutate: ((variables) => {
17
17
  set({ isWaiting: true });
@@ -26,7 +26,7 @@ export const createMutation = (mutationFn, options = {}) => {
26
26
  isError: false,
27
27
  response,
28
28
  responseUpdatedAt: Date.now(),
29
- error: null,
29
+ error: undefined,
30
30
  errorUpdatedAt: null,
31
31
  });
32
32
  onSuccess(response, variables, stateBeforeMutate);
@@ -26,8 +26,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
26
26
  * If the data is empty, it will just fetch the first page.
27
27
  *
28
28
  * You can ignore this if your query is not paginated.
29
+ *
30
+ * @returns Promise that will always get resolved.
29
31
  */
30
- fetchNextPage: () => void;
32
+ fetchNextPage: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
31
33
  /**
32
34
  * Set query state (data, error, etc) to initial state.
33
35
  */
@@ -55,7 +57,7 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
55
57
  isRefetchError: boolean;
56
58
  isPreviousData: boolean;
57
59
  isOptimisticData: boolean;
58
- error: TError | null;
60
+ error: TError | undefined;
59
61
  errorUpdatedAt: number | null;
60
62
  retryCount: number;
61
63
  isGoingToRetry: boolean;
@@ -97,8 +99,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
97
99
  * If data fetched successfully but then an error occured, `isError` will be `false` but `isRefetchError` will be `true`.
98
100
  */
99
101
  isError: false;
100
- data: null;
101
- response: null;
102
+ data: undefined;
103
+ response: undefined;
102
104
  responseUpdatedAt: null;
103
105
  } | {
104
106
  status: 'success';
@@ -113,8 +115,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
113
115
  isLoading: false;
114
116
  isSuccess: false;
115
117
  isError: true;
116
- data: null;
117
- response: null;
118
+ data: undefined;
119
+ response: undefined;
118
120
  responseUpdatedAt: null;
119
121
  });
120
122
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
@@ -13,10 +13,10 @@ const INITIAL_QUERY_STATE = {
13
13
  isRefetchError: false,
14
14
  isPreviousData: false,
15
15
  isOptimisticData: false,
16
- data: null,
17
- response: null,
16
+ data: undefined,
17
+ response: undefined,
18
18
  responseUpdatedAt: null,
19
- error: null,
19
+ error: undefined,
20
20
  errorUpdatedAt: null,
21
21
  retryCount: 0,
22
22
  isGoingToRetry: false,
@@ -87,7 +87,7 @@ export const createQuery = (queryFn, options = {}) => {
87
87
  .then((response) => {
88
88
  if (preventReplaceResponse.get(keyHash)) {
89
89
  set({ isWaiting: false });
90
- return;
90
+ return resolve(get());
91
91
  }
92
92
  responseAllPages.push(response);
93
93
  const newPageParam = getNextPageParam(response, responseAllPages.length);
@@ -109,10 +109,10 @@ export const createQuery = (queryFn, options = {}) => {
109
109
  isOptimisticData: false,
110
110
  data: responseAllPages.reduce((prev, responseCurrentPage) => {
111
111
  return select(responseCurrentPage, { key, data: prev });
112
- }, null),
112
+ }, undefined),
113
113
  response,
114
114
  responseUpdatedAt: Date.now(),
115
- error: null,
115
+ error: undefined,
116
116
  errorUpdatedAt: null,
117
117
  retryCount: 0,
118
118
  pageParam: newPageParam,
@@ -128,7 +128,6 @@ export const createQuery = (queryFn, options = {}) => {
128
128
  }
129
129
  set(nextState);
130
130
  onSuccess(response, stateBeforeCallQuery);
131
- resolve(get());
132
131
  })
133
132
  .catch((error) => {
134
133
  const prevState = get();
@@ -142,7 +141,7 @@ export const createQuery = (queryFn, options = {}) => {
142
141
  data: responseAllPages.length
143
142
  ? responseAllPages.reduce((prev, response) => {
144
143
  return select(response, { key, data: prev });
145
- }, null)
144
+ }, undefined)
146
145
  : prevState.data,
147
146
  error,
148
147
  errorUpdatedAt,
@@ -155,7 +154,7 @@ export const createQuery = (queryFn, options = {}) => {
155
154
  status: 'error',
156
155
  isLoading: false,
157
156
  isError: true,
158
- data: null,
157
+ data: undefined,
159
158
  error,
160
159
  errorUpdatedAt,
161
160
  isGoingToRetry: shouldRetry,
@@ -169,10 +168,10 @@ export const createQuery = (queryFn, options = {}) => {
169
168
  }, delay));
170
169
  }
171
170
  onError(error, stateBeforeCallQuery);
172
- resolve(get());
173
171
  })
174
172
  .finally(() => {
175
173
  onSettled(stateBeforeCallQuery);
174
+ resolve(get());
176
175
  });
177
176
  };
178
177
  callQuery();
@@ -184,18 +183,27 @@ export const createQuery = (queryFn, options = {}) => {
184
183
  return;
185
184
  forceFetch();
186
185
  };
187
- const fetchNextPage = () => {
186
+ const fetchNextPage = () => new Promise((resolve) => {
187
+ const state = get();
188
188
  if (typeof options.getNextPageParam !== 'function') {
189
- return console.warn('fetchNextPage with invalid getNextPageParam option');
189
+ console.warn('fetchNextPage with invalid getNextPageParam option');
190
+ return resolve(state);
190
191
  }
191
- const state = get();
192
192
  const { isLoading, isWaitingNextPage, data, hasNextPage, pageParam, pageParams } = state;
193
193
  if (isLoading)
194
- return forceFetch();
194
+ return resolve(forceFetch());
195
195
  if (isWaitingNextPage || !hasNextPage)
196
- return;
196
+ return resolve(state);
197
+ let shouldcancel = false;
198
+ const cancel = () => {
199
+ shouldcancel = true;
200
+ };
201
+ onBeforeFetch(cancel, state);
202
+ if (shouldcancel)
203
+ return resolve(state);
197
204
  set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
198
205
  clearTimeout(retryNextPageTimeoutId.get(keyHash));
206
+ const stateBeforeCallQuery = get();
199
207
  queryFn(key, { ...state, pageParam })
200
208
  .then((response) => {
201
209
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -208,6 +216,7 @@ export const createQuery = (queryFn, options = {}) => {
208
216
  pageParams: pageParams.concat(newPageParam),
209
217
  hasNextPage: hasValue(newPageParam),
210
218
  });
219
+ onSuccess(response, stateBeforeCallQuery);
211
220
  })
212
221
  .catch((error) => {
213
222
  const prevState = get();
@@ -225,8 +234,13 @@ export const createQuery = (queryFn, options = {}) => {
225
234
  fetchNextPage();
226
235
  }, delay));
227
236
  }
237
+ onError(error, stateBeforeCallQuery);
238
+ })
239
+ .finally(() => {
240
+ onSettled(stateBeforeCallQuery);
241
+ resolve(get());
228
242
  });
229
- };
243
+ });
230
244
  return {
231
245
  ...INITIAL_QUERY_STATE,
232
246
  key,
@@ -323,7 +337,7 @@ export const createQuery = (queryFn, options = {}) => {
323
337
  isError: false,
324
338
  response,
325
339
  responseUpdatedAt: skipRevalidation ? Date.now() : null,
326
- data: select(response, { key: key, data: null }),
340
+ data: select(response, { key: key, data: undefined }),
327
341
  pageParam: newPageParam,
328
342
  pageParams: [undefined, newPageParam],
329
343
  hasNextPage: hasValue(newPageParam),
@@ -361,7 +375,7 @@ export const createQuery = (queryFn, options = {}) => {
361
375
  useQuery.set(key, {
362
376
  isOptimisticData: true,
363
377
  response: optimisticResponse,
364
- data: select(optimisticResponse, { key: key, data: null }),
378
+ data: select(optimisticResponse, { key: key, data: undefined }),
365
379
  });
366
380
  preventReplaceResponse.set(prevState.keyHash, true);
367
381
  const revert = () => {
@@ -7,9 +7,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
7
7
  isWaiting: boolean;
8
8
  isSuccess: boolean;
9
9
  isError: boolean;
10
- response: TResponse | null;
10
+ response: TResponse | undefined;
11
11
  responseUpdatedAt: number | null;
12
- error: TError | null;
12
+ error: TError | undefined;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
15
  * Mutate function.
@@ -9,9 +9,9 @@ export const createMutation = (mutationFn, options = {}) => {
9
9
  isWaiting: false,
10
10
  isSuccess: false,
11
11
  isError: false,
12
- response: null,
12
+ response: undefined,
13
13
  responseUpdatedAt: null,
14
- error: null,
14
+ error: undefined,
15
15
  errorUpdatedAt: null,
16
16
  mutate: ((variables) => {
17
17
  set({ isWaiting: true });
@@ -26,7 +26,7 @@ export const createMutation = (mutationFn, options = {}) => {
26
26
  isError: false,
27
27
  response,
28
28
  responseUpdatedAt: Date.now(),
29
- error: null,
29
+ error: undefined,
30
30
  errorUpdatedAt: null,
31
31
  });
32
32
  onSuccess(response, variables, stateBeforeMutate);
@@ -25,8 +25,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
25
25
  * If the data is empty, it will just fetch the first page.
26
26
  *
27
27
  * You can ignore this if your query is not paginated.
28
+ *
29
+ * @returns Promise that will always get resolved.
28
30
  */
29
- fetchNextPage: () => void;
31
+ fetchNextPage: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
30
32
  /**
31
33
  * Set query state (data, error, etc) to initial state.
32
34
  */
@@ -54,7 +56,7 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
54
56
  isRefetchError: boolean;
55
57
  isPreviousData: boolean;
56
58
  isOptimisticData: boolean;
57
- error: TError | null;
59
+ error: TError | undefined;
58
60
  errorUpdatedAt: number | null;
59
61
  retryCount: number;
60
62
  isGoingToRetry: boolean;
@@ -96,8 +98,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
96
98
  * If data fetched successfully but then an error occured, `isError` will be `false` but `isRefetchError` will be `true`.
97
99
  */
98
100
  isError: false;
99
- data: null;
100
- response: null;
101
+ data: undefined;
102
+ response: undefined;
101
103
  responseUpdatedAt: null;
102
104
  } | {
103
105
  status: 'success';
@@ -112,8 +114,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
112
114
  isLoading: false;
113
115
  isSuccess: false;
114
116
  isError: true;
115
- data: null;
116
- response: null;
117
+ data: undefined;
118
+ response: undefined;
117
119
  responseUpdatedAt: null;
118
120
  });
119
121
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
@@ -12,10 +12,10 @@ const INITIAL_QUERY_STATE = {
12
12
  isRefetchError: false,
13
13
  isPreviousData: false,
14
14
  isOptimisticData: false,
15
- data: null,
16
- response: null,
15
+ data: undefined,
16
+ response: undefined,
17
17
  responseUpdatedAt: null,
18
- error: null,
18
+ error: undefined,
19
19
  errorUpdatedAt: null,
20
20
  retryCount: 0,
21
21
  isGoingToRetry: false,
@@ -86,7 +86,7 @@ export const createQuery = (queryFn, options = {}) => {
86
86
  .then((response) => {
87
87
  if (preventReplaceResponse.get(keyHash)) {
88
88
  set({ isWaiting: false });
89
- return;
89
+ return resolve(get());
90
90
  }
91
91
  responseAllPages.push(response);
92
92
  const newPageParam = getNextPageParam(response, responseAllPages.length);
@@ -108,10 +108,10 @@ export const createQuery = (queryFn, options = {}) => {
108
108
  isOptimisticData: false,
109
109
  data: responseAllPages.reduce((prev, responseCurrentPage) => {
110
110
  return select(responseCurrentPage, { key, data: prev });
111
- }, null),
111
+ }, undefined),
112
112
  response,
113
113
  responseUpdatedAt: Date.now(),
114
- error: null,
114
+ error: undefined,
115
115
  errorUpdatedAt: null,
116
116
  retryCount: 0,
117
117
  pageParam: newPageParam,
@@ -127,7 +127,6 @@ export const createQuery = (queryFn, options = {}) => {
127
127
  }
128
128
  set(nextState);
129
129
  onSuccess(response, stateBeforeCallQuery);
130
- resolve(get());
131
130
  })
132
131
  .catch((error) => {
133
132
  const prevState = get();
@@ -141,7 +140,7 @@ export const createQuery = (queryFn, options = {}) => {
141
140
  data: responseAllPages.length
142
141
  ? responseAllPages.reduce((prev, response) => {
143
142
  return select(response, { key, data: prev });
144
- }, null)
143
+ }, undefined)
145
144
  : prevState.data,
146
145
  error,
147
146
  errorUpdatedAt,
@@ -154,7 +153,7 @@ export const createQuery = (queryFn, options = {}) => {
154
153
  status: 'error',
155
154
  isLoading: false,
156
155
  isError: true,
157
- data: null,
156
+ data: undefined,
158
157
  error,
159
158
  errorUpdatedAt,
160
159
  isGoingToRetry: shouldRetry,
@@ -168,10 +167,10 @@ export const createQuery = (queryFn, options = {}) => {
168
167
  }, delay));
169
168
  }
170
169
  onError(error, stateBeforeCallQuery);
171
- resolve(get());
172
170
  })
173
171
  .finally(() => {
174
172
  onSettled(stateBeforeCallQuery);
173
+ resolve(get());
175
174
  });
176
175
  };
177
176
  callQuery();
@@ -183,18 +182,27 @@ export const createQuery = (queryFn, options = {}) => {
183
182
  return;
184
183
  forceFetch();
185
184
  };
186
- const fetchNextPage = () => {
185
+ const fetchNextPage = () => new Promise((resolve) => {
186
+ const state = get();
187
187
  if (typeof options.getNextPageParam !== 'function') {
188
- return console.warn('fetchNextPage with invalid getNextPageParam option');
188
+ console.warn('fetchNextPage with invalid getNextPageParam option');
189
+ return resolve(state);
189
190
  }
190
- const state = get();
191
191
  const { isLoading, isWaitingNextPage, data, hasNextPage, pageParam, pageParams } = state;
192
192
  if (isLoading)
193
- return forceFetch();
193
+ return resolve(forceFetch());
194
194
  if (isWaitingNextPage || !hasNextPage)
195
- return;
195
+ return resolve(state);
196
+ let shouldcancel = false;
197
+ const cancel = () => {
198
+ shouldcancel = true;
199
+ };
200
+ onBeforeFetch(cancel, state);
201
+ if (shouldcancel)
202
+ return resolve(state);
196
203
  set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
197
204
  clearTimeout(retryNextPageTimeoutId.get(keyHash));
205
+ const stateBeforeCallQuery = get();
198
206
  queryFn(key, { ...state, pageParam })
199
207
  .then((response) => {
200
208
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -207,6 +215,7 @@ export const createQuery = (queryFn, options = {}) => {
207
215
  pageParams: pageParams.concat(newPageParam),
208
216
  hasNextPage: hasValue(newPageParam),
209
217
  });
218
+ onSuccess(response, stateBeforeCallQuery);
210
219
  })
211
220
  .catch((error) => {
212
221
  const prevState = get();
@@ -224,8 +233,13 @@ export const createQuery = (queryFn, options = {}) => {
224
233
  fetchNextPage();
225
234
  }, delay));
226
235
  }
236
+ onError(error, stateBeforeCallQuery);
237
+ })
238
+ .finally(() => {
239
+ onSettled(stateBeforeCallQuery);
240
+ resolve(get());
227
241
  });
228
- };
242
+ });
229
243
  return {
230
244
  ...INITIAL_QUERY_STATE,
231
245
  key,
@@ -322,7 +336,7 @@ export const createQuery = (queryFn, options = {}) => {
322
336
  isError: false,
323
337
  response,
324
338
  responseUpdatedAt: skipRevalidation ? Date.now() : null,
325
- data: select(response, { key: key, data: null }),
339
+ data: select(response, { key: key, data: undefined }),
326
340
  pageParam: newPageParam,
327
341
  pageParams: [undefined, newPageParam],
328
342
  hasNextPage: hasValue(newPageParam),
@@ -360,7 +374,7 @@ export const createQuery = (queryFn, options = {}) => {
360
374
  useQuery.set(key, {
361
375
  isOptimisticData: true,
362
376
  response: optimisticResponse,
363
- data: select(optimisticResponse, { key: key, data: null }),
377
+ data: select(optimisticResponse, { key: key, data: undefined }),
364
378
  });
365
379
  preventReplaceResponse.set(prevState.keyHash, true);
366
380
  const revert = () => {
@@ -7,9 +7,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
7
7
  isWaiting: boolean;
8
8
  isSuccess: boolean;
9
9
  isError: boolean;
10
- response: TResponse | null;
10
+ response: TResponse | undefined;
11
11
  responseUpdatedAt: number | null;
12
- error: TError | null;
12
+ error: TError | undefined;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
15
  * Mutate function.
@@ -12,9 +12,9 @@ const createMutation = (mutationFn, options = {}) => {
12
12
  isWaiting: false,
13
13
  isSuccess: false,
14
14
  isError: false,
15
- response: null,
15
+ response: undefined,
16
16
  responseUpdatedAt: null,
17
- error: null,
17
+ error: undefined,
18
18
  errorUpdatedAt: null,
19
19
  mutate: ((variables) => {
20
20
  set({ isWaiting: true });
@@ -29,7 +29,7 @@ const createMutation = (mutationFn, options = {}) => {
29
29
  isError: false,
30
30
  response,
31
31
  responseUpdatedAt: Date.now(),
32
- error: null,
32
+ error: undefined,
33
33
  errorUpdatedAt: null,
34
34
  });
35
35
  onSuccess(response, variables, stateBeforeMutate);
@@ -26,8 +26,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
26
26
  * If the data is empty, it will just fetch the first page.
27
27
  *
28
28
  * You can ignore this if your query is not paginated.
29
+ *
30
+ * @returns Promise that will always get resolved.
29
31
  */
30
- fetchNextPage: () => void;
32
+ fetchNextPage: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
31
33
  /**
32
34
  * Set query state (data, error, etc) to initial state.
33
35
  */
@@ -55,7 +57,7 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
55
57
  isRefetchError: boolean;
56
58
  isPreviousData: boolean;
57
59
  isOptimisticData: boolean;
58
- error: TError | null;
60
+ error: TError | undefined;
59
61
  errorUpdatedAt: number | null;
60
62
  retryCount: number;
61
63
  isGoingToRetry: boolean;
@@ -97,8 +99,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
97
99
  * If data fetched successfully but then an error occured, `isError` will be `false` but `isRefetchError` will be `true`.
98
100
  */
99
101
  isError: false;
100
- data: null;
101
- response: null;
102
+ data: undefined;
103
+ response: undefined;
102
104
  responseUpdatedAt: null;
103
105
  } | {
104
106
  status: 'success';
@@ -113,8 +115,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
113
115
  isLoading: false;
114
116
  isSuccess: false;
115
117
  isError: true;
116
- data: null;
117
- response: null;
118
+ data: undefined;
119
+ response: undefined;
118
120
  responseUpdatedAt: null;
119
121
  });
120
122
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
@@ -16,10 +16,10 @@ const INITIAL_QUERY_STATE = {
16
16
  isRefetchError: false,
17
17
  isPreviousData: false,
18
18
  isOptimisticData: false,
19
- data: null,
20
- response: null,
19
+ data: undefined,
20
+ response: undefined,
21
21
  responseUpdatedAt: null,
22
- error: null,
22
+ error: undefined,
23
23
  errorUpdatedAt: null,
24
24
  retryCount: 0,
25
25
  isGoingToRetry: false,
@@ -90,7 +90,7 @@ const createQuery = (queryFn, options = {}) => {
90
90
  .then((response) => {
91
91
  if (preventReplaceResponse.get(keyHash)) {
92
92
  set({ isWaiting: false });
93
- return;
93
+ return resolve(get());
94
94
  }
95
95
  responseAllPages.push(response);
96
96
  const newPageParam = getNextPageParam(response, responseAllPages.length);
@@ -112,10 +112,10 @@ const createQuery = (queryFn, options = {}) => {
112
112
  isOptimisticData: false,
113
113
  data: responseAllPages.reduce((prev, responseCurrentPage) => {
114
114
  return select(responseCurrentPage, { key, data: prev });
115
- }, null),
115
+ }, undefined),
116
116
  response,
117
117
  responseUpdatedAt: Date.now(),
118
- error: null,
118
+ error: undefined,
119
119
  errorUpdatedAt: null,
120
120
  retryCount: 0,
121
121
  pageParam: newPageParam,
@@ -131,7 +131,6 @@ const createQuery = (queryFn, options = {}) => {
131
131
  }
132
132
  set(nextState);
133
133
  onSuccess(response, stateBeforeCallQuery);
134
- resolve(get());
135
134
  })
136
135
  .catch((error) => {
137
136
  const prevState = get();
@@ -145,7 +144,7 @@ const createQuery = (queryFn, options = {}) => {
145
144
  data: responseAllPages.length
146
145
  ? responseAllPages.reduce((prev, response) => {
147
146
  return select(response, { key, data: prev });
148
- }, null)
147
+ }, undefined)
149
148
  : prevState.data,
150
149
  error,
151
150
  errorUpdatedAt,
@@ -158,7 +157,7 @@ const createQuery = (queryFn, options = {}) => {
158
157
  status: 'error',
159
158
  isLoading: false,
160
159
  isError: true,
161
- data: null,
160
+ data: undefined,
162
161
  error,
163
162
  errorUpdatedAt,
164
163
  isGoingToRetry: shouldRetry,
@@ -172,10 +171,10 @@ const createQuery = (queryFn, options = {}) => {
172
171
  }, delay));
173
172
  }
174
173
  onError(error, stateBeforeCallQuery);
175
- resolve(get());
176
174
  })
177
175
  .finally(() => {
178
176
  onSettled(stateBeforeCallQuery);
177
+ resolve(get());
179
178
  });
180
179
  };
181
180
  callQuery();
@@ -187,18 +186,27 @@ const createQuery = (queryFn, options = {}) => {
187
186
  return;
188
187
  forceFetch();
189
188
  };
190
- const fetchNextPage = () => {
189
+ const fetchNextPage = () => new Promise((resolve) => {
190
+ const state = get();
191
191
  if (typeof options.getNextPageParam !== 'function') {
192
- return console.warn('fetchNextPage with invalid getNextPageParam option');
192
+ console.warn('fetchNextPage with invalid getNextPageParam option');
193
+ return resolve(state);
193
194
  }
194
- const state = get();
195
195
  const { isLoading, isWaitingNextPage, data, hasNextPage, pageParam, pageParams } = state;
196
196
  if (isLoading)
197
- return forceFetch();
197
+ return resolve(forceFetch());
198
198
  if (isWaitingNextPage || !hasNextPage)
199
- return;
199
+ return resolve(state);
200
+ let shouldcancel = false;
201
+ const cancel = () => {
202
+ shouldcancel = true;
203
+ };
204
+ onBeforeFetch(cancel, state);
205
+ if (shouldcancel)
206
+ return resolve(state);
200
207
  set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
201
208
  clearTimeout(retryNextPageTimeoutId.get(keyHash));
209
+ const stateBeforeCallQuery = get();
202
210
  queryFn(key, { ...state, pageParam })
203
211
  .then((response) => {
204
212
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -211,6 +219,7 @@ const createQuery = (queryFn, options = {}) => {
211
219
  pageParams: pageParams.concat(newPageParam),
212
220
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
213
221
  });
222
+ onSuccess(response, stateBeforeCallQuery);
214
223
  })
215
224
  .catch((error) => {
216
225
  const prevState = get();
@@ -228,8 +237,13 @@ const createQuery = (queryFn, options = {}) => {
228
237
  fetchNextPage();
229
238
  }, delay));
230
239
  }
240
+ onError(error, stateBeforeCallQuery);
241
+ })
242
+ .finally(() => {
243
+ onSettled(stateBeforeCallQuery);
244
+ resolve(get());
231
245
  });
232
- };
246
+ });
233
247
  return {
234
248
  ...INITIAL_QUERY_STATE,
235
249
  key,
@@ -326,7 +340,7 @@ const createQuery = (queryFn, options = {}) => {
326
340
  isError: false,
327
341
  response,
328
342
  responseUpdatedAt: skipRevalidation ? Date.now() : null,
329
- data: select(response, { key: key, data: null }),
343
+ data: select(response, { key: key, data: undefined }),
330
344
  pageParam: newPageParam,
331
345
  pageParams: [undefined, newPageParam],
332
346
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
@@ -364,7 +378,7 @@ const createQuery = (queryFn, options = {}) => {
364
378
  useQuery.set(key, {
365
379
  isOptimisticData: true,
366
380
  response: optimisticResponse,
367
- data: select(optimisticResponse, { key: key, data: null }),
381
+ data: select(optimisticResponse, { key: key, data: undefined }),
368
382
  });
369
383
  preventReplaceResponse.set(prevState.keyHash, true);
370
384
  const revert = () => {
@@ -7,9 +7,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
7
7
  isWaiting: boolean;
8
8
  isSuccess: boolean;
9
9
  isError: boolean;
10
- response: TResponse | null;
10
+ response: TResponse | undefined;
11
11
  responseUpdatedAt: number | null;
12
- error: TError | null;
12
+ error: TError | undefined;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
15
  * Mutate function.
@@ -12,9 +12,9 @@ const createMutation = (mutationFn, options = {}) => {
12
12
  isWaiting: false,
13
13
  isSuccess: false,
14
14
  isError: false,
15
- response: null,
15
+ response: undefined,
16
16
  responseUpdatedAt: null,
17
- error: null,
17
+ error: undefined,
18
18
  errorUpdatedAt: null,
19
19
  mutate: ((variables) => {
20
20
  set({ isWaiting: true });
@@ -29,7 +29,7 @@ const createMutation = (mutationFn, options = {}) => {
29
29
  isError: false,
30
30
  response,
31
31
  responseUpdatedAt: Date.now(),
32
- error: null,
32
+ error: undefined,
33
33
  errorUpdatedAt: null,
34
34
  });
35
35
  onSuccess(response, variables, stateBeforeMutate);
@@ -25,8 +25,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
25
25
  * If the data is empty, it will just fetch the first page.
26
26
  *
27
27
  * You can ignore this if your query is not paginated.
28
+ *
29
+ * @returns Promise that will always get resolved.
28
30
  */
29
- fetchNextPage: () => void;
31
+ fetchNextPage: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
30
32
  /**
31
33
  * Set query state (data, error, etc) to initial state.
32
34
  */
@@ -54,7 +56,7 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
54
56
  isRefetchError: boolean;
55
57
  isPreviousData: boolean;
56
58
  isOptimisticData: boolean;
57
- error: TError | null;
59
+ error: TError | undefined;
58
60
  errorUpdatedAt: number | null;
59
61
  retryCount: number;
60
62
  isGoingToRetry: boolean;
@@ -96,8 +98,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
96
98
  * If data fetched successfully but then an error occured, `isError` will be `false` but `isRefetchError` will be `true`.
97
99
  */
98
100
  isError: false;
99
- data: null;
100
- response: null;
101
+ data: undefined;
102
+ response: undefined;
101
103
  responseUpdatedAt: null;
102
104
  } | {
103
105
  status: 'success';
@@ -112,8 +114,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
112
114
  isLoading: false;
113
115
  isSuccess: false;
114
116
  isError: true;
115
- data: null;
116
- response: null;
117
+ data: undefined;
118
+ response: undefined;
117
119
  responseUpdatedAt: null;
118
120
  });
119
121
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
@@ -15,10 +15,10 @@ const INITIAL_QUERY_STATE = {
15
15
  isRefetchError: false,
16
16
  isPreviousData: false,
17
17
  isOptimisticData: false,
18
- data: null,
19
- response: null,
18
+ data: undefined,
19
+ response: undefined,
20
20
  responseUpdatedAt: null,
21
- error: null,
21
+ error: undefined,
22
22
  errorUpdatedAt: null,
23
23
  retryCount: 0,
24
24
  isGoingToRetry: false,
@@ -89,7 +89,7 @@ const createQuery = (queryFn, options = {}) => {
89
89
  .then((response) => {
90
90
  if (preventReplaceResponse.get(keyHash)) {
91
91
  set({ isWaiting: false });
92
- return;
92
+ return resolve(get());
93
93
  }
94
94
  responseAllPages.push(response);
95
95
  const newPageParam = getNextPageParam(response, responseAllPages.length);
@@ -111,10 +111,10 @@ const createQuery = (queryFn, options = {}) => {
111
111
  isOptimisticData: false,
112
112
  data: responseAllPages.reduce((prev, responseCurrentPage) => {
113
113
  return select(responseCurrentPage, { key, data: prev });
114
- }, null),
114
+ }, undefined),
115
115
  response,
116
116
  responseUpdatedAt: Date.now(),
117
- error: null,
117
+ error: undefined,
118
118
  errorUpdatedAt: null,
119
119
  retryCount: 0,
120
120
  pageParam: newPageParam,
@@ -130,7 +130,6 @@ const createQuery = (queryFn, options = {}) => {
130
130
  }
131
131
  set(nextState);
132
132
  onSuccess(response, stateBeforeCallQuery);
133
- resolve(get());
134
133
  })
135
134
  .catch((error) => {
136
135
  const prevState = get();
@@ -144,7 +143,7 @@ const createQuery = (queryFn, options = {}) => {
144
143
  data: responseAllPages.length
145
144
  ? responseAllPages.reduce((prev, response) => {
146
145
  return select(response, { key, data: prev });
147
- }, null)
146
+ }, undefined)
148
147
  : prevState.data,
149
148
  error,
150
149
  errorUpdatedAt,
@@ -157,7 +156,7 @@ const createQuery = (queryFn, options = {}) => {
157
156
  status: 'error',
158
157
  isLoading: false,
159
158
  isError: true,
160
- data: null,
159
+ data: undefined,
161
160
  error,
162
161
  errorUpdatedAt,
163
162
  isGoingToRetry: shouldRetry,
@@ -171,10 +170,10 @@ const createQuery = (queryFn, options = {}) => {
171
170
  }, delay));
172
171
  }
173
172
  onError(error, stateBeforeCallQuery);
174
- resolve(get());
175
173
  })
176
174
  .finally(() => {
177
175
  onSettled(stateBeforeCallQuery);
176
+ resolve(get());
178
177
  });
179
178
  };
180
179
  callQuery();
@@ -186,18 +185,27 @@ const createQuery = (queryFn, options = {}) => {
186
185
  return;
187
186
  forceFetch();
188
187
  };
189
- const fetchNextPage = () => {
188
+ const fetchNextPage = () => new Promise((resolve) => {
189
+ const state = get();
190
190
  if (typeof options.getNextPageParam !== 'function') {
191
- return console.warn('fetchNextPage with invalid getNextPageParam option');
191
+ console.warn('fetchNextPage with invalid getNextPageParam option');
192
+ return resolve(state);
192
193
  }
193
- const state = get();
194
194
  const { isLoading, isWaitingNextPage, data, hasNextPage, pageParam, pageParams } = state;
195
195
  if (isLoading)
196
- return forceFetch();
196
+ return resolve(forceFetch());
197
197
  if (isWaitingNextPage || !hasNextPage)
198
- return;
198
+ return resolve(state);
199
+ let shouldcancel = false;
200
+ const cancel = () => {
201
+ shouldcancel = true;
202
+ };
203
+ onBeforeFetch(cancel, state);
204
+ if (shouldcancel)
205
+ return resolve(state);
199
206
  set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
200
207
  clearTimeout(retryNextPageTimeoutId.get(keyHash));
208
+ const stateBeforeCallQuery = get();
201
209
  queryFn(key, { ...state, pageParam })
202
210
  .then((response) => {
203
211
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -210,6 +218,7 @@ const createQuery = (queryFn, options = {}) => {
210
218
  pageParams: pageParams.concat(newPageParam),
211
219
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
212
220
  });
221
+ onSuccess(response, stateBeforeCallQuery);
213
222
  })
214
223
  .catch((error) => {
215
224
  const prevState = get();
@@ -227,8 +236,13 @@ const createQuery = (queryFn, options = {}) => {
227
236
  fetchNextPage();
228
237
  }, delay));
229
238
  }
239
+ onError(error, stateBeforeCallQuery);
240
+ })
241
+ .finally(() => {
242
+ onSettled(stateBeforeCallQuery);
243
+ resolve(get());
230
244
  });
231
- };
245
+ });
232
246
  return {
233
247
  ...INITIAL_QUERY_STATE,
234
248
  key,
@@ -325,7 +339,7 @@ const createQuery = (queryFn, options = {}) => {
325
339
  isError: false,
326
340
  response,
327
341
  responseUpdatedAt: skipRevalidation ? Date.now() : null,
328
- data: select(response, { key: key, data: null }),
342
+ data: select(response, { key: key, data: undefined }),
329
343
  pageParam: newPageParam,
330
344
  pageParams: [undefined, newPageParam],
331
345
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
@@ -363,7 +377,7 @@ const createQuery = (queryFn, options = {}) => {
363
377
  useQuery.set(key, {
364
378
  isOptimisticData: true,
365
379
  response: optimisticResponse,
366
- data: select(optimisticResponse, { key: key, data: null }),
380
+ data: select(optimisticResponse, { key: key, data: undefined }),
367
381
  });
368
382
  preventReplaceResponse.set(prevState.keyHash, true);
369
383
  const revert = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floppy-disk",
3
- "version": "2.4.0",
3
+ "version": "2.5.0-beta.2",
4
4
  "description": "FloppyDisk - lightweight, simple, and powerful state management library",
5
5
  "keywords": [
6
6
  "state",