floppy-disk 2.2.0-beta.3 → 2.3.0-beta.1

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
@@ -661,10 +661,11 @@ function PokemonListPage() {
661
661
  **Note:**
662
662
 
663
663
  - The default stale time is 3 seconds.
664
- - The default error retry attempt is 1 time, and retry delay is 3 seconds.
665
- - The default reactivity of a query is `(s) => [s.data, s.error]`.
666
- (For paginated: `(s) => [s.data, s.error, s.isWaitingNextPage, s.hasNextPage]`)
667
- - You can change the `defaultDeps` on `createQuery` options.
664
+ - The default error retry attempt is 1 time, and retry delay is 2 seconds.
665
+ - The default reactivity of a query is:
666
+ `(s) => [s.data, s.error, s.isWaitingNextPage, s.hasNextPage]`
667
+ - Note that by default, subscribers don't listen to `isWaiting` state.
668
+ - You can change the `defaultDeps` on `createQuery` options.
668
669
 
669
670
  ### Mutation
670
671
 
@@ -724,6 +725,7 @@ function SaveProduct() {
724
725
 
725
726
  const { revert, invalidate } = useProductQuery.optimisticUpdate({
726
727
  key: { id: payload.id },
728
+ response: payload,
727
729
  });
728
730
 
729
731
  mutate(payload).then(({ response, error }) => {
@@ -795,3 +797,11 @@ function PokemonsPage() {
795
797
  return <div>...</div>;
796
798
  }
797
799
  ```
800
+
801
+ <br>
802
+
803
+ ---
804
+
805
+ <p align="center">
806
+ View official documentation on <a href="https://floppy-disk.vercel.app/">floppy-disk.vercel.app</a>
807
+ </p>
@@ -12,7 +12,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
12
12
  error: TError | null;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
- * Mutate function is a promise that will always resolve.
15
+ * Mutate function.
16
+ *
17
+ * @returns Promise that will always get resolved.
16
18
  */
17
19
  mutate: TVar extends undefined ? () => Promise<{
18
20
  response?: TResponse;
@@ -14,8 +14,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
14
14
  fetch: () => void;
15
15
  /**
16
16
  * Will be called even if the data is still fresh (not stale).
17
+ *
18
+ * @returns Promise that will always get resolved.
17
19
  */
18
- forceFetch: () => void;
20
+ forceFetch: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
19
21
  /**
20
22
  * Fetch next page if has next page.
21
23
  *
@@ -187,7 +189,7 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
187
189
  * IMPORTANT NOTE: Put this on the root component or parent component, before any component subscribed!
188
190
  */
189
191
  setInitialResponse: (options: {
190
- key?: TKey;
192
+ key?: TKey | null;
191
193
  response: TResponse;
192
194
  skipRevalidation?: boolean;
193
195
  }) => void;
@@ -221,5 +223,9 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
221
223
  revert: () => void;
222
224
  invalidate: () => void;
223
225
  };
226
+ /**
227
+ * Use query with suspense mode.
228
+ */
229
+ suspend: (key?: TKey | null) => QueryState<TKey, TResponse, TData, TError>;
224
230
  };
225
231
  export declare const createQuery: <TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown>(queryFn: (key: TKey, state: QueryState<TKey, TResponse, TData, TError>) => Promise<TResponse>, options?: CreateQueryOptions<TKey, TResponse, TData, TError>) => UseQuery<TKey, TResponse, TData, TError>;
@@ -56,7 +56,7 @@ export const createQuery = (queryFn, options = {}) => {
56
56
  const delay = (typeof retryDelay === 'function' ? retryDelay(error, prevState) : retryDelay) || 0;
57
57
  return { shouldRetry, delay };
58
58
  };
59
- const forceFetch = () => {
59
+ const forceFetch = () => new Promise((resolve) => {
60
60
  const responseAllPages = [];
61
61
  const newPageParams = [undefined];
62
62
  let pageParam = undefined;
@@ -114,6 +114,7 @@ export const createQuery = (queryFn, options = {}) => {
114
114
  hasNextPage: hasValue(newPageParam),
115
115
  });
116
116
  onSuccess(response, stateBeforeCallQuery);
117
+ resolve(get());
117
118
  })
118
119
  .catch((error) => {
119
120
  const prevState = get();
@@ -147,20 +148,21 @@ export const createQuery = (queryFn, options = {}) => {
147
148
  pageParam,
148
149
  hasNextPage: hasValue(pageParam),
149
150
  });
150
- if (shouldRetry) {
151
+ if (shouldRetry && typeof window !== 'undefined') {
151
152
  retryTimeoutId.set(keyHash, window.setTimeout(() => {
152
153
  set({ retryCount: prevState.retryCount + 1 });
153
154
  callQuery();
154
155
  }, delay));
155
156
  }
156
157
  onError(error, stateBeforeCallQuery);
158
+ resolve(get());
157
159
  })
158
160
  .finally(() => {
159
161
  onSettled(stateBeforeCallQuery);
160
162
  });
161
163
  };
162
164
  callQuery();
163
- };
165
+ });
164
166
  const fetch = () => {
165
167
  const { responseUpdatedAt } = get();
166
168
  const isStale = Date.now() > Number(responseUpdatedAt) + staleTime;
@@ -341,5 +343,14 @@ export const createQuery = (queryFn, options = {}) => {
341
343
  const invalidate = () => useQuery.invalidateSpecificKey(key);
342
344
  return { revert, invalidate };
343
345
  };
346
+ useQuery.suspend = (key) => {
347
+ // eslint-disable-next-line react-hooks/rules-of-hooks
348
+ const state = useQuery(key);
349
+ if (state.isLoading)
350
+ throw state.forceFetch();
351
+ if (state.isError)
352
+ throw state.error;
353
+ return state;
354
+ };
344
355
  return useQuery;
345
356
  };
@@ -12,7 +12,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
12
12
  error: TError | null;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
- * Mutate function is a promise that will always resolve.
15
+ * Mutate function.
16
+ *
17
+ * @returns Promise that will always get resolved.
16
18
  */
17
19
  mutate: TVar extends undefined ? () => Promise<{
18
20
  response?: TResponse;
@@ -14,8 +14,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
14
14
  fetch: () => void;
15
15
  /**
16
16
  * Will be called even if the data is still fresh (not stale).
17
+ *
18
+ * @returns Promise that will always get resolved.
17
19
  */
18
- forceFetch: () => void;
20
+ forceFetch: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
19
21
  /**
20
22
  * Fetch next page if has next page.
21
23
  *
@@ -187,7 +189,7 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
187
189
  * IMPORTANT NOTE: Put this on the root component or parent component, before any component subscribed!
188
190
  */
189
191
  setInitialResponse: (options: {
190
- key?: TKey;
192
+ key?: TKey | null;
191
193
  response: TResponse;
192
194
  skipRevalidation?: boolean;
193
195
  }) => void;
@@ -221,5 +223,9 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
221
223
  revert: () => void;
222
224
  invalidate: () => void;
223
225
  };
226
+ /**
227
+ * Use query with suspense mode.
228
+ */
229
+ suspend: (key?: TKey | null) => QueryState<TKey, TResponse, TData, TError>;
224
230
  };
225
231
  export declare const createQuery: <TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown>(queryFn: (key: TKey, state: QueryState<TKey, TResponse, TData, TError>) => Promise<TResponse>, options?: CreateQueryOptions<TKey, TResponse, TData, TError>) => UseQuery<TKey, TResponse, TData, TError>;
@@ -56,7 +56,7 @@ export const createQuery = (queryFn, options = {}) => {
56
56
  const delay = (typeof retryDelay === 'function' ? retryDelay(error, prevState) : retryDelay) || 0;
57
57
  return { shouldRetry, delay };
58
58
  };
59
- const forceFetch = () => {
59
+ const forceFetch = () => new Promise((resolve) => {
60
60
  const responseAllPages = [];
61
61
  const newPageParams = [undefined];
62
62
  let pageParam = undefined;
@@ -114,6 +114,7 @@ export const createQuery = (queryFn, options = {}) => {
114
114
  hasNextPage: hasValue(newPageParam),
115
115
  });
116
116
  onSuccess(response, stateBeforeCallQuery);
117
+ resolve(get());
117
118
  })
118
119
  .catch((error) => {
119
120
  const prevState = get();
@@ -147,20 +148,21 @@ export const createQuery = (queryFn, options = {}) => {
147
148
  pageParam,
148
149
  hasNextPage: hasValue(pageParam),
149
150
  });
150
- if (shouldRetry) {
151
+ if (shouldRetry && typeof window !== 'undefined') {
151
152
  retryTimeoutId.set(keyHash, window.setTimeout(() => {
152
153
  set({ retryCount: prevState.retryCount + 1 });
153
154
  callQuery();
154
155
  }, delay));
155
156
  }
156
157
  onError(error, stateBeforeCallQuery);
158
+ resolve(get());
157
159
  })
158
160
  .finally(() => {
159
161
  onSettled(stateBeforeCallQuery);
160
162
  });
161
163
  };
162
164
  callQuery();
163
- };
165
+ });
164
166
  const fetch = () => {
165
167
  const { responseUpdatedAt } = get();
166
168
  const isStale = Date.now() > Number(responseUpdatedAt) + staleTime;
@@ -341,5 +343,14 @@ export const createQuery = (queryFn, options = {}) => {
341
343
  const invalidate = () => useQuery.invalidateSpecificKey(key);
342
344
  return { revert, invalidate };
343
345
  };
346
+ useQuery.suspend = (key) => {
347
+ // eslint-disable-next-line react-hooks/rules-of-hooks
348
+ const state = useQuery(key);
349
+ if (state.isLoading)
350
+ throw state.forceFetch();
351
+ if (state.isError)
352
+ throw state.error;
353
+ return state;
354
+ };
344
355
  return useQuery;
345
356
  };
@@ -12,7 +12,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
12
12
  error: TError | null;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
- * Mutate function is a promise that will always resolve.
15
+ * Mutate function.
16
+ *
17
+ * @returns Promise that will always get resolved.
16
18
  */
17
19
  mutate: TVar extends undefined ? () => Promise<{
18
20
  response?: TResponse;
@@ -14,8 +14,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
14
14
  fetch: () => void;
15
15
  /**
16
16
  * Will be called even if the data is still fresh (not stale).
17
+ *
18
+ * @returns Promise that will always get resolved.
17
19
  */
18
- forceFetch: () => void;
20
+ forceFetch: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
19
21
  /**
20
22
  * Fetch next page if has next page.
21
23
  *
@@ -187,7 +189,7 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
187
189
  * IMPORTANT NOTE: Put this on the root component or parent component, before any component subscribed!
188
190
  */
189
191
  setInitialResponse: (options: {
190
- key?: TKey;
192
+ key?: TKey | null;
191
193
  response: TResponse;
192
194
  skipRevalidation?: boolean;
193
195
  }) => void;
@@ -221,5 +223,9 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
221
223
  revert: () => void;
222
224
  invalidate: () => void;
223
225
  };
226
+ /**
227
+ * Use query with suspense mode.
228
+ */
229
+ suspend: (key?: TKey | null) => QueryState<TKey, TResponse, TData, TError>;
224
230
  };
225
231
  export declare const createQuery: <TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown>(queryFn: (key: TKey, state: QueryState<TKey, TResponse, TData, TError>) => Promise<TResponse>, options?: CreateQueryOptions<TKey, TResponse, TData, TError>) => UseQuery<TKey, TResponse, TData, TError>;
@@ -59,7 +59,7 @@ const createQuery = (queryFn, options = {}) => {
59
59
  const delay = (typeof retryDelay === 'function' ? retryDelay(error, prevState) : retryDelay) || 0;
60
60
  return { shouldRetry, delay };
61
61
  };
62
- const forceFetch = () => {
62
+ const forceFetch = () => new Promise((resolve) => {
63
63
  const responseAllPages = [];
64
64
  const newPageParams = [undefined];
65
65
  let pageParam = undefined;
@@ -117,6 +117,7 @@ const createQuery = (queryFn, options = {}) => {
117
117
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
118
118
  });
119
119
  onSuccess(response, stateBeforeCallQuery);
120
+ resolve(get());
120
121
  })
121
122
  .catch((error) => {
122
123
  const prevState = get();
@@ -150,20 +151,21 @@ const createQuery = (queryFn, options = {}) => {
150
151
  pageParam,
151
152
  hasNextPage: (0, utils_1.hasValue)(pageParam),
152
153
  });
153
- if (shouldRetry) {
154
+ if (shouldRetry && typeof window !== 'undefined') {
154
155
  retryTimeoutId.set(keyHash, window.setTimeout(() => {
155
156
  set({ retryCount: prevState.retryCount + 1 });
156
157
  callQuery();
157
158
  }, delay));
158
159
  }
159
160
  onError(error, stateBeforeCallQuery);
161
+ resolve(get());
160
162
  })
161
163
  .finally(() => {
162
164
  onSettled(stateBeforeCallQuery);
163
165
  });
164
166
  };
165
167
  callQuery();
166
- };
168
+ });
167
169
  const fetch = () => {
168
170
  const { responseUpdatedAt } = get();
169
171
  const isStale = Date.now() > Number(responseUpdatedAt) + staleTime;
@@ -344,6 +346,15 @@ const createQuery = (queryFn, options = {}) => {
344
346
  const invalidate = () => useQuery.invalidateSpecificKey(key);
345
347
  return { revert, invalidate };
346
348
  };
349
+ useQuery.suspend = (key) => {
350
+ // eslint-disable-next-line react-hooks/rules-of-hooks
351
+ const state = useQuery(key);
352
+ if (state.isLoading)
353
+ throw state.forceFetch();
354
+ if (state.isError)
355
+ throw state.error;
356
+ return state;
357
+ };
347
358
  return useQuery;
348
359
  };
349
360
  exports.createQuery = createQuery;
@@ -12,7 +12,9 @@ export type MutationState<TVar, TResponse = any, TError = unknown> = {
12
12
  error: TError | null;
13
13
  errorUpdatedAt: number | null;
14
14
  /**
15
- * Mutate function is a promise that will always resolve.
15
+ * Mutate function.
16
+ *
17
+ * @returns Promise that will always get resolved.
16
18
  */
17
19
  mutate: TVar extends undefined ? () => Promise<{
18
20
  response?: TResponse;
@@ -14,8 +14,10 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
14
14
  fetch: () => void;
15
15
  /**
16
16
  * Will be called even if the data is still fresh (not stale).
17
+ *
18
+ * @returns Promise that will always get resolved.
17
19
  */
18
- forceFetch: () => void;
20
+ forceFetch: () => Promise<QueryState<TKey, TResponse, TData, TError>>;
19
21
  /**
20
22
  * Fetch next page if has next page.
21
23
  *
@@ -187,7 +189,7 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
187
189
  * IMPORTANT NOTE: Put this on the root component or parent component, before any component subscribed!
188
190
  */
189
191
  setInitialResponse: (options: {
190
- key?: TKey;
192
+ key?: TKey | null;
191
193
  response: TResponse;
192
194
  skipRevalidation?: boolean;
193
195
  }) => void;
@@ -221,5 +223,9 @@ export type UseQuery<TKey extends StoreKey = StoreKey, TResponse = any, TData =
221
223
  revert: () => void;
222
224
  invalidate: () => void;
223
225
  };
226
+ /**
227
+ * Use query with suspense mode.
228
+ */
229
+ suspend: (key?: TKey | null) => QueryState<TKey, TResponse, TData, TError>;
224
230
  };
225
231
  export declare const createQuery: <TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown>(queryFn: (key: TKey, state: QueryState<TKey, TResponse, TData, TError>) => Promise<TResponse>, options?: CreateQueryOptions<TKey, TResponse, TData, TError>) => UseQuery<TKey, TResponse, TData, TError>;
@@ -59,7 +59,7 @@ const createQuery = (queryFn, options = {}) => {
59
59
  const delay = (typeof retryDelay === 'function' ? retryDelay(error, prevState) : retryDelay) || 0;
60
60
  return { shouldRetry, delay };
61
61
  };
62
- const forceFetch = () => {
62
+ const forceFetch = () => new Promise((resolve) => {
63
63
  const responseAllPages = [];
64
64
  const newPageParams = [undefined];
65
65
  let pageParam = undefined;
@@ -117,6 +117,7 @@ const createQuery = (queryFn, options = {}) => {
117
117
  hasNextPage: (0, utils_1.hasValue)(newPageParam),
118
118
  });
119
119
  onSuccess(response, stateBeforeCallQuery);
120
+ resolve(get());
120
121
  })
121
122
  .catch((error) => {
122
123
  const prevState = get();
@@ -150,20 +151,21 @@ const createQuery = (queryFn, options = {}) => {
150
151
  pageParam,
151
152
  hasNextPage: (0, utils_1.hasValue)(pageParam),
152
153
  });
153
- if (shouldRetry) {
154
+ if (shouldRetry && typeof window !== 'undefined') {
154
155
  retryTimeoutId.set(keyHash, window.setTimeout(() => {
155
156
  set({ retryCount: prevState.retryCount + 1 });
156
157
  callQuery();
157
158
  }, delay));
158
159
  }
159
160
  onError(error, stateBeforeCallQuery);
161
+ resolve(get());
160
162
  })
161
163
  .finally(() => {
162
164
  onSettled(stateBeforeCallQuery);
163
165
  });
164
166
  };
165
167
  callQuery();
166
- };
168
+ });
167
169
  const fetch = () => {
168
170
  const { responseUpdatedAt } = get();
169
171
  const isStale = Date.now() > Number(responseUpdatedAt) + staleTime;
@@ -344,6 +346,15 @@ const createQuery = (queryFn, options = {}) => {
344
346
  const invalidate = () => useQuery.invalidateSpecificKey(key);
345
347
  return { revert, invalidate };
346
348
  };
349
+ useQuery.suspend = (key) => {
350
+ // eslint-disable-next-line react-hooks/rules-of-hooks
351
+ const state = useQuery(key);
352
+ if (state.isLoading)
353
+ throw state.forceFetch();
354
+ if (state.isError)
355
+ throw state.error;
356
+ return state;
357
+ };
347
358
  return useQuery;
348
359
  };
349
360
  exports.createQuery = createQuery;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floppy-disk",
3
- "version": "2.2.0-beta.3",
3
+ "version": "2.3.0-beta.1",
4
4
  "description": "FloppyDisk - lightweight, simple, and powerful state management library",
5
5
  "keywords": [
6
6
  "state",