@robohall/react-query-factory 2.1.6 → 2.2.0
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 +71 -4
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -218,6 +218,23 @@ queryClient.invalidateQueries(describeInstances({ MaxResults: 20 }));
|
|
|
218
218
|
|
|
219
219
|
---
|
|
220
220
|
|
|
221
|
+
## Which pattern?
|
|
222
|
+
|
|
223
|
+
| Pattern | Use when |
|
|
224
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
225
|
+
| Basic | API returns a single, non-paginated response |
|
|
226
|
+
| Async iterator | `queryFn` returns an `AsyncIterable` (e.g. an AWS SDK v3 paginator) — no cursor wiring required |
|
|
227
|
+
| Crawl-then-render | Paginated API; UI needs all data before it's useful (dropdowns, counts, totals) |
|
|
228
|
+
| Render-while-crawling | Paginated API; UI can show partial results as pages arrive |
|
|
229
|
+
| On-demand (`.infinite()`) | Paginated API; user clicks "load more" or navigates pages |
|
|
230
|
+
| Client-side search | Paginated API; find a subset without server-side filtering — stop crawling when condition is met |
|
|
231
|
+
|
|
232
|
+
**Async iterator** is a `queryFn` style, not a display pattern — combine it with any crawl pattern above when your SDK provides a paginator function.
|
|
233
|
+
|
|
234
|
+
**Composition** and **Invalidation** apply alongside any pattern: use composition when multiple views share one cache entry, invalidation after a mutation changes server state.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
221
238
|
## Installation
|
|
222
239
|
|
|
223
240
|
```bash
|
|
@@ -247,11 +264,25 @@ const { data: partial } = useQuery(
|
|
|
247
264
|
);
|
|
248
265
|
```
|
|
249
266
|
|
|
267
|
+
### Error behavior
|
|
268
|
+
|
|
269
|
+
If any page fetch throws, the error propagates immediately — there is no per-page retry or partial-result fallback. TanStack Query receives the error exactly as it would from a single-page `queryFn` and applies its normal `retry`, `throwOnError`, and error-state semantics.
|
|
270
|
+
|
|
271
|
+
When TanStack retries, the crawl starts over from `initialPageParam`. There is no resume-from-page-N.
|
|
272
|
+
|
|
273
|
+
The crawl also respects the abort signal between pages. When the signal fires (component unmounts, query superseded by a newer one), the loop exits after the current in-flight page completes. TanStack does not commit the partial result.
|
|
274
|
+
|
|
250
275
|
---
|
|
251
276
|
|
|
252
277
|
## Async iterator queryFns
|
|
253
278
|
|
|
254
|
-
When `queryFn` returns an `AsyncIterable`, the library
|
|
279
|
+
When `queryFn` returns an `AsyncIterable`, the library walks it with `for await...of` instead of calling `queryFn` repeatedly with successive `pageParam` values. The cursor lives inside the iterator rather than in `getNextPageParam` — that's the only meaningful difference from a cursor-based factory. `shouldFetchNextPage`, `reduce`, `crawlOptions`, and `.infinite()` all work identically.
|
|
280
|
+
|
|
281
|
+
One caveat for `.infinite()`: `getNextPageParam` is still required, but its role shifts — instead of wiring each individual API page, it records where the next batch should start when the user loads more.
|
|
282
|
+
|
|
283
|
+
Without `shouldFetchNextPage`, the library exhausts the iterator on every call — every page, every time.
|
|
284
|
+
|
|
285
|
+
Any source of `AsyncIterable<TPage>` works:
|
|
255
286
|
|
|
256
287
|
```typescript
|
|
257
288
|
import { paginateDescribeInstances } from '@aws-sdk/client-ec2';
|
|
@@ -273,9 +304,7 @@ const describeInstances = queryFactory({
|
|
|
273
304
|
});
|
|
274
305
|
```
|
|
275
306
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
For `.infinite()` mode, `getNextPageParam` is required to capture the next virtual page's starting cursor from the last yielded item. AWS SDK v3 paginators accept a `startingToken` to resume from a specific position — wire `ctx.pageParam` to it:
|
|
307
|
+
For `.infinite()`, wire `ctx.pageParam` to the iterator's resume parameter so each batch starts from the right position:
|
|
279
308
|
|
|
280
309
|
```typescript
|
|
281
310
|
const describeInstances = queryFactory({
|
|
@@ -388,6 +417,24 @@ The `.infinite()` key includes an `'infinite'` segment to keep it separate from
|
|
|
388
417
|
|
|
389
418
|
---
|
|
390
419
|
|
|
420
|
+
## Performance
|
|
421
|
+
|
|
422
|
+
TanStack Query's default `staleTime` is `0` — data is considered stale immediately, so a background refetch fires on every mount, window focus, and reconnect. For a single-page query that's one API call; for a crawling factory it's the full crawl repeated. Set `staleTime` in the factory config to match how often the underlying data actually changes:
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
const describeInstances = queryFactory({
|
|
426
|
+
queryKey: ['ec2:DescribeInstances'],
|
|
427
|
+
staleTime: 60_000, // re-crawl at most once per minute
|
|
428
|
+
// ...
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Child factories inherit `staleTime` and all other standard options from the parent, so setting it once on the root factory covers every derived view.
|
|
433
|
+
|
|
434
|
+
When freshness requirements allow it, `refetchOnWindowFocus` and `refetchOnMount` can be set to `false` on the factory for the same reason — each is a potential full re-crawl.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
391
438
|
## Public API
|
|
392
439
|
|
|
393
440
|
### `queryFactory(config)`
|
|
@@ -440,6 +487,26 @@ Return type of `factory(params)`. Pass directly to `useQuery()`. Contains an `in
|
|
|
440
487
|
|
|
441
488
|
Return type of `factory.infinite(params)`. Pass directly to `useInfiniteQuery()`. The `select` field is typed to `InfiniteData<TData, TPageParam>`, which prevents accidental use with `useQuery`.
|
|
442
489
|
|
|
490
|
+
### `FactoryParams<F>`
|
|
491
|
+
|
|
492
|
+
Extracts the params type from a factory — the first argument of a factory call. Useful for typing component props that accept factory params.
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
import type { FactoryParams } from '@robohall/react-query-factory';
|
|
496
|
+
|
|
497
|
+
type Params = FactoryParams<typeof describeInstances>; // → DescribeInstancesRequest
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### `FactoryCrawlOptions<F>`
|
|
501
|
+
|
|
502
|
+
Extracts the crawl options type from a factory — the second argument of a factory call. Useful for typing helpers or components that accept crawl options.
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
import type { FactoryCrawlOptions } from '@robohall/react-query-factory';
|
|
506
|
+
|
|
507
|
+
type CrawlOpts = FactoryCrawlOptions<typeof describeInstances>; // → { minResults?: number }
|
|
508
|
+
```
|
|
509
|
+
|
|
443
510
|
---
|
|
444
511
|
|
|
445
512
|
## Running the sandbox
|
package/dist/index.d.mts
CHANGED
|
@@ -100,6 +100,10 @@ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelecte
|
|
|
100
100
|
(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
|
|
101
101
|
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
|
|
102
102
|
}
|
|
103
|
+
/** Extracts the params type from a factory — the first argument of a factory call. */
|
|
104
|
+
type FactoryParams<F> = F extends QueryFactory<infer TParams, any, any, any, any, any, any> ? TParams : never;
|
|
105
|
+
/** Extracts the crawl options type from a factory — the second argument of a factory call. */
|
|
106
|
+
type FactoryCrawlOptions<F> = F extends QueryFactory<any, any, any, any, any, infer TCrawlOptions, any> ? TCrawlOptions : never;
|
|
103
107
|
/**
|
|
104
108
|
* Creates a standalone query factory with pagination and reduce. When `reduce` is
|
|
105
109
|
* present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
|
|
@@ -208,4 +212,4 @@ declare function queryFactory<TParams = void, TData = unknown, TError = Error, T
|
|
|
208
212
|
shouldFetchNextPage: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
|
|
209
213
|
}): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
|
|
210
214
|
|
|
211
|
-
export { type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
|
|
215
|
+
export { type FactoryCrawlOptions, type FactoryParams, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
|
package/dist/index.d.ts
CHANGED
|
@@ -100,6 +100,10 @@ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelecte
|
|
|
100
100
|
(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
|
|
101
101
|
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
|
|
102
102
|
}
|
|
103
|
+
/** Extracts the params type from a factory — the first argument of a factory call. */
|
|
104
|
+
type FactoryParams<F> = F extends QueryFactory<infer TParams, any, any, any, any, any, any> ? TParams : never;
|
|
105
|
+
/** Extracts the crawl options type from a factory — the second argument of a factory call. */
|
|
106
|
+
type FactoryCrawlOptions<F> = F extends QueryFactory<any, any, any, any, any, infer TCrawlOptions, any> ? TCrawlOptions : never;
|
|
103
107
|
/**
|
|
104
108
|
* Creates a standalone query factory with pagination and reduce. When `reduce` is
|
|
105
109
|
* present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
|
|
@@ -208,4 +212,4 @@ declare function queryFactory<TParams = void, TData = unknown, TError = Error, T
|
|
|
208
212
|
shouldFetchNextPage: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
|
|
209
213
|
}): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
|
|
210
214
|
|
|
211
|
-
export { type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
|
|
215
|
+
export { type FactoryCrawlOptions, type FactoryParams, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robohall/react-query-factory",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A factory abstraction for TanStack Query (React Query) with composable keys, crawling support, and automatic infinite query generation",
|
|
5
5
|
"author": "Robert Hall",
|
|
6
6
|
"license": "MIT",
|