react-redux-cache 0.16.1 → 0.18.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 +17 -19
- package/dist/createActions.d.ts +4 -4
- package/dist/createCache.d.ts +28 -24
- package/dist/createCache.js +8 -1
- package/dist/createCacheReducer.js +13 -5
- package/dist/createSelectors.d.ts +4 -4
- package/dist/index.js +5 -1
- package/dist/mutate.js +12 -13
- package/dist/query.js +32 -16
- package/dist/types.d.ts +15 -9
- package/dist/useMutation.d.ts +1 -1
- package/dist/useMutation.js +1 -3
- package/dist/useQuery.d.ts +2 -2
- package/dist/useQuery.js +2 -3
- package/dist/utilsAndConstants.d.ts +2 -1
- package/dist/utilsAndConstants.js +5 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
# react-redux-cache (RRC)
|
|
11
11
|
|
|
12
|
-
### Supports both `Redux` and `Zustand`
|
|
12
|
+
### Supports both `Redux` and `Zustand` (check /example)
|
|
13
13
|
|
|
14
14
|
**Powerful**, **performant** yet **lightweight** data fetching and caching library that supports **normalization** unlike `React Query` and `RTK-Query`, while having similar but not over-engineered, simple interface. Another advantage over `RTK-Query` is that it **doesn't use Immer** ([perf issue](https://github.com/reduxjs/redux-toolkit/issues/4793)). Covered with tests, fully typed and written on Typescript.
|
|
15
15
|
|
|
@@ -44,11 +44,11 @@ Examples of states, generated by cache reducer from `/example` project:
|
|
|
44
44
|
// each query has its own map of query states, stored by cache key, which is generated from query params
|
|
45
45
|
getUser: {
|
|
46
46
|
"2": {result: 2, params: 2, expiresAt: 1727217298025},
|
|
47
|
-
"3": {loading:
|
|
47
|
+
"3": {loading: Promise<...>, params: 3}
|
|
48
48
|
},
|
|
49
49
|
getUsers: {
|
|
50
50
|
// example of paginated state under custom cache key
|
|
51
|
-
"
|
|
51
|
+
"feed": {
|
|
52
52
|
result: {items: [0,1,2], page: 1},
|
|
53
53
|
params: {page: 1}
|
|
54
54
|
}
|
|
@@ -82,11 +82,11 @@ Examples of states, generated by cache reducer from `/example` project:
|
|
|
82
82
|
params: 2,
|
|
83
83
|
expiresAt: 1727217298025
|
|
84
84
|
},
|
|
85
|
-
"3": {loading:
|
|
85
|
+
"3": {loading: Promise<...>, params: 3}
|
|
86
86
|
},
|
|
87
87
|
getUsers: {
|
|
88
88
|
// example of paginated state under custom cache key
|
|
89
|
-
"
|
|
89
|
+
"feed": {
|
|
90
90
|
result: {
|
|
91
91
|
items: [
|
|
92
92
|
{id: 0, bank: {id: "0", name: "Bank 0"}, name: "User 0 *"},
|
|
@@ -137,13 +137,13 @@ Examples of states, generated by cache reducer from `/example` project:
|
|
|
137
137
|
|
|
138
138
|
```sh
|
|
139
139
|
# required
|
|
140
|
-
npm
|
|
140
|
+
npm i react-redux-cache react
|
|
141
141
|
|
|
142
142
|
# without react-redux
|
|
143
|
-
npm
|
|
143
|
+
npm i react-redux-cache react fast-deep-equal
|
|
144
144
|
|
|
145
145
|
# all required and optional peers
|
|
146
|
-
npm
|
|
146
|
+
npm i react-redux-cache react react-redux fast-deep-equal
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
### Initialization
|
|
@@ -221,15 +221,13 @@ const store = configureStore({
|
|
|
221
221
|
Zustand:
|
|
222
222
|
```typescript
|
|
223
223
|
type State = {[cache.name]: ReturnType<typeof reducer>}
|
|
224
|
-
type Actions = {dispatch: (action:
|
|
225
|
-
|
|
224
|
+
type Actions = {dispatch: (action: Parameters<typeof reducer>[1]) => void}
|
|
225
|
+
|
|
226
|
+
const initialState = {[cache.name]: getInitialState()}
|
|
226
227
|
|
|
227
228
|
export const useStore = create<State & Actions>((set, get) => ({
|
|
228
|
-
|
|
229
|
-
[cache.name]: reducer(
|
|
230
|
-
dispatch: (action: CacheAction) => {
|
|
231
|
-
set({cache: reducer(get().cache, action)})
|
|
232
|
-
},
|
|
229
|
+
...initialState,
|
|
230
|
+
dispatch: (action) => set({[cache.name]: reducer(get()[cache.name], action)}),
|
|
233
231
|
}))
|
|
234
232
|
|
|
235
233
|
const store = {dispatch: useStore.getState().dispatch, getState: useStore.getState}
|
|
@@ -272,7 +270,7 @@ export const removeUser = (async (id, _, abortSignal) => {
|
|
|
272
270
|
|
|
273
271
|
### Usage
|
|
274
272
|
|
|
275
|
-
Please check `example/` folder (`npm run example` to run).
|
|
273
|
+
Please check `example/` folder (`npm run example` to run). There are examples for both Redux and Zustand.
|
|
276
274
|
|
|
277
275
|
#### UserScreen.tsx
|
|
278
276
|
```typescript
|
|
@@ -306,7 +304,7 @@ export const UserScreen = () => {
|
|
|
306
304
|
|
|
307
305
|
#### Error handling
|
|
308
306
|
|
|
309
|
-
Queries and mutations are wrapped in try/catch, so any error will lead to cancelling of any updates to the state except
|
|
307
|
+
Queries and mutations are wrapped in try/catch, so any error will lead to cancelling of any updates to the state except loading state and the caught error. If you still want to make some state updates, or just want to use thrown errors only for unexpected cases, consider returning expected errors as a part of the result:
|
|
310
308
|
|
|
311
309
|
```typescript
|
|
312
310
|
export const updateBank = (async (bank) => {
|
|
@@ -433,7 +431,7 @@ Here is an example of `getUsers` query configuration with pagination support. Yo
|
|
|
433
431
|
queries: {
|
|
434
432
|
getUsers: {
|
|
435
433
|
query: getUsers,
|
|
436
|
-
getCacheKey: () => '
|
|
434
|
+
getCacheKey: () => 'feed', // single cache key is used for all pages
|
|
437
435
|
mergeResults: (oldResult, {result: newResult}) => {
|
|
438
436
|
if (!oldResult || newResult.page === 1) {
|
|
439
437
|
return newResult
|
|
@@ -441,7 +439,7 @@ Here is an example of `getUsers` query configuration with pagination support. Yo
|
|
|
441
439
|
if (newResult.page === oldResult.page + 1) {
|
|
442
440
|
return {
|
|
443
441
|
...newResult,
|
|
444
|
-
items:
|
|
442
|
+
items: oldResult.items.concat(newResult.items),
|
|
445
443
|
}
|
|
446
444
|
}
|
|
447
445
|
return oldResult
|
package/dist/createActions.d.ts
CHANGED
|
@@ -3,20 +3,20 @@ import { CacheState } from './types';
|
|
|
3
3
|
export type Actions<N extends string = string, T extends Typenames = Typenames, QP = unknown, QR = unknown, MP = unknown, MR = unknown> = ReturnType<typeof createActions<N, T, QP, QR, MP, MR>>;
|
|
4
4
|
export declare const createActions: <N extends string, T extends Typenames, QP, QR, MP, MR>(name: N) => {
|
|
5
5
|
updateQueryStateAndEntities: {
|
|
6
|
-
<K extends keyof (QP | QR)>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryState<QP[K], QR[K]>>, entityChanges?: EntityChanges<T>): {
|
|
6
|
+
<K extends keyof (QP | QR)>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryState<T, QP[K], QR[K]>>, entityChanges?: EntityChanges<T>): {
|
|
7
7
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
8
8
|
queryKey: K;
|
|
9
9
|
queryCacheKey: Key;
|
|
10
|
-
state: Partial<QueryState<QP[K], QR[K]>> | undefined;
|
|
10
|
+
state: Partial<QueryState<T, QP[K], QR[K]>> | undefined;
|
|
11
11
|
entityChanges: EntityChanges<T> | undefined;
|
|
12
12
|
};
|
|
13
13
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
14
14
|
};
|
|
15
15
|
updateMutationStateAndEntities: {
|
|
16
|
-
<K extends keyof (MP | MR)>(mutationKey: K, state?: Partial<MutationState<MP[K], MR[K]>>, entityChanges?: EntityChanges<T>): {
|
|
16
|
+
<K extends keyof (MP | MR)>(mutationKey: K, state?: Partial<MutationState<T, MP[K], MR[K]>>, entityChanges?: EntityChanges<T>): {
|
|
17
17
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
18
18
|
mutationKey: K;
|
|
19
|
-
state: Partial<MutationState<MP[K], MR[K]>> | undefined;
|
|
19
|
+
state: Partial<MutationState<T, MP[K], MR[K]>> | undefined;
|
|
20
20
|
entityChanges: EntityChanges<T> | undefined;
|
|
21
21
|
};
|
|
22
22
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
package/dist/createCache.d.ts
CHANGED
|
@@ -21,12 +21,12 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
21
21
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
22
22
|
queryKey: keyof QP & keyof QR;
|
|
23
23
|
queryCacheKey: Key;
|
|
24
|
-
state: Partial<import("./types").QueryState<QP[keyof QP & keyof QR], QR[keyof QP & keyof QR]>> | undefined;
|
|
24
|
+
state: Partial<import("./types").QueryState<T, QP[keyof QP & keyof QR], QR[keyof QP & keyof QR]>> | undefined;
|
|
25
25
|
entityChanges: import("./types").EntityChanges<T> | undefined;
|
|
26
26
|
} | {
|
|
27
27
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
28
28
|
mutationKey: keyof MP & keyof MR;
|
|
29
|
-
state: Partial<import("./types").MutationState<MP[keyof MP & keyof MR], MR[keyof MP & keyof MR]>> | undefined;
|
|
29
|
+
state: Partial<import("./types").MutationState<T, MP[keyof MP & keyof MR], MR[keyof MP & keyof MR]>> | undefined;
|
|
30
30
|
entityChanges: import("./types").EntityChanges<T> | undefined;
|
|
31
31
|
} | {
|
|
32
32
|
type: `@rrc/${N}/mergeEntityChanges`;
|
|
@@ -54,21 +54,21 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
54
54
|
actions: {
|
|
55
55
|
/** Updates query state, and optionally merges entity changes in a single action. */
|
|
56
56
|
updateQueryStateAndEntities: {
|
|
57
|
-
<K extends keyof QP & keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryState<QP[K], QR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<T> | undefined): {
|
|
57
|
+
<K extends keyof QP & keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryState<T, QP[K], QR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<T> | undefined): {
|
|
58
58
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
59
59
|
queryKey: K;
|
|
60
60
|
queryCacheKey: Key;
|
|
61
|
-
state: Partial<import("./types").QueryState<QP[K], QR[K]>> | undefined;
|
|
61
|
+
state: Partial<import("./types").QueryState<T, QP[K], QR[K]>> | undefined;
|
|
62
62
|
entityChanges: import("./types").EntityChanges<T> | undefined;
|
|
63
63
|
};
|
|
64
64
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
65
65
|
};
|
|
66
66
|
/** Updates mutation state, and optionally merges entity changes in a single action. */
|
|
67
67
|
updateMutationStateAndEntities: {
|
|
68
|
-
<K extends keyof MP & keyof MR>(mutationKey: K, state?: Partial<import("./types").MutationState<MP[K], MR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<T> | undefined): {
|
|
68
|
+
<K extends keyof MP & keyof MR>(mutationKey: K, state?: Partial<import("./types").MutationState<T, MP[K], MR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<T> | undefined): {
|
|
69
69
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
70
70
|
mutationKey: K;
|
|
71
|
-
state: Partial<import("./types").MutationState<MP[K], MR[K]>> | undefined;
|
|
71
|
+
state: Partial<import("./types").MutationState<T, MP[K], MR[K]>> | undefined;
|
|
72
72
|
entityChanges: import("./types").EntityChanges<T> | undefined;
|
|
73
73
|
};
|
|
74
74
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
@@ -133,11 +133,11 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
133
133
|
/** This is a cacheStateSelector from createCache options, or default one if was not provided. */
|
|
134
134
|
selectCacheState: (state: any) => import("./types").CacheState<T, QP, QR, MP, MR>;
|
|
135
135
|
/** Selects query state. */
|
|
136
|
-
selectQueryState: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => import("./types").QueryState<QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>;
|
|
136
|
+
selectQueryState: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => import("./types").QueryState<T, QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>;
|
|
137
137
|
/** Selects query latest result. */
|
|
138
138
|
selectQueryResult: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => (QK extends keyof QP & keyof QR ? QR[QK] : never) | undefined;
|
|
139
139
|
/** Selects query loading state. */
|
|
140
|
-
selectQueryLoading: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) =>
|
|
140
|
+
selectQueryLoading: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => false | Promise<import("./types").NormalizedQueryResponse<T, QK extends keyof QP & keyof QR ? QR[QK] : never>>;
|
|
141
141
|
/** Selects query latest error. */
|
|
142
142
|
selectQueryError: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => Error | undefined;
|
|
143
143
|
/** Selects query latest params. */
|
|
@@ -145,11 +145,11 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
145
145
|
/** Selects query latest expiresAt. */
|
|
146
146
|
selectQueryExpiresAt: <QK extends keyof QP | keyof QR>(state: unknown, query: QK, cacheKey: Key) => number | undefined;
|
|
147
147
|
/** Selects mutation state. */
|
|
148
|
-
selectMutationState: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) => import("./types").MutationState<MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MR[MK] : never>;
|
|
148
|
+
selectMutationState: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) => import("./types").MutationState<T, MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MR[MK] : never>;
|
|
149
149
|
/** Selects mutation latest result. */
|
|
150
150
|
selectMutationResult: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) => (MK extends keyof MP & keyof MR ? MR[MK] : never) | undefined;
|
|
151
151
|
/** Selects mutation loading state. */
|
|
152
|
-
selectMutationLoading: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) =>
|
|
152
|
+
selectMutationLoading: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) => false | Promise<import("./types").NormalizedQueryResponse<T, MK extends keyof MP & keyof MR ? MR[MK] : never>>;
|
|
153
153
|
/** Selects mutation latest error. */
|
|
154
154
|
selectMutationError: <MK extends keyof MP | keyof MR>(state: unknown, mutation: MK) => Error | undefined;
|
|
155
155
|
/** Selects mutation latest params. */
|
|
@@ -168,13 +168,15 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
168
168
|
mutate: <MK extends keyof (MP & MR)>(options: MutateOptions<N, T, QP, QR, MP, MR, MK>) => Promise<MutationResult<MK extends keyof MP & keyof MR ? MR[MK] : never>>;
|
|
169
169
|
};
|
|
170
170
|
/** Fetches query when params change and subscribes to query state changes (except `expiresAt` field). */
|
|
171
|
-
useQuery: <QK extends keyof (QP & QR)>(options: Parameters<typeof useQuery<N, T, QP, QR, MP, MR, QK>>[3]) => readonly [Omit<import("./types").QueryState<QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, T, QP, QR, QK, MP, MR>, "params" | "onlyIfExpired">> | undefined) => Promise<QueryResult<QK extends infer T_1 ? T_1 extends QK ? T_1 extends keyof QP & keyof QR ? QR[T_1] : never : never : never>>];
|
|
171
|
+
useQuery: <QK extends keyof (QP & QR)>(options: Parameters<typeof useQuery<N, T, QP, QR, MP, MR, QK>>[3]) => readonly [Omit<import("./types").QueryState<T, QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, T, QP, QR, QK, MP, MR>, "params" | "onlyIfExpired">> | undefined) => Promise<QueryResult<QK extends infer T_1 ? T_1 extends QK ? T_1 extends keyof QP & keyof QR ? QR[T_1] : never : never : never>>];
|
|
172
172
|
/** Subscribes to provided mutation state and provides mutate function. */
|
|
173
|
-
useMutation: <MK extends keyof (MP & MR)>(options: Parameters<typeof useMutation<N, T, QP, QR, MP, MR, MK>>[3]) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<MutationResult<MK extends infer T_1 ? T_1 extends MK ? T_1 extends keyof MP & keyof MR ? MR[T_1] : never : never : never>>, import("./types").MutationState<MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
|
173
|
+
useMutation: <MK extends keyof (MP & MR)>(options: Parameters<typeof useMutation<N, T, QP, QR, MP, MR, MK>>[3]) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<MutationResult<MK extends infer T_1 ? T_1 extends MK ? T_1 extends keyof MP & keyof MR ? MR[T_1] : never : never : never>>, import("./types").MutationState<T, MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
|
174
174
|
/** useSelector + selectEntityById. */
|
|
175
175
|
useSelectEntityById: <TN extends keyof T>(id: Key | null | undefined, typename: TN) => T[TN] | undefined;
|
|
176
176
|
};
|
|
177
177
|
utils: {
|
|
178
|
+
/** Generates the initial state by calling a reducer. Not needed for redux — it already generates it the same way when creating the store. */
|
|
179
|
+
getInitialState: () => import("./types").CacheState<T, QP, QR, MP, MR>;
|
|
178
180
|
/** Apply changes to the entities map.
|
|
179
181
|
* @returns `undefined` if nothing to change, otherwise new `EntitiesMap<T>` with applied changes. */
|
|
180
182
|
applyEntityChanges: (entities: Parameters<typeof applyEntityChanges<T>>[0], changes: Parameters<typeof applyEntityChanges<T>>[1]) => import("./types").EntitiesMap<T> | undefined;
|
|
@@ -203,12 +205,12 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(partialCach
|
|
|
203
205
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
204
206
|
queryKey: keyof QP & keyof QR;
|
|
205
207
|
queryCacheKey: Key;
|
|
206
|
-
state: Partial<import("./types").QueryState<QP[keyof QP & keyof QR], QR[keyof QP & keyof QR]>> | undefined;
|
|
208
|
+
state: Partial<import("./types").QueryState<Typenames, QP[keyof QP & keyof QR], QR[keyof QP & keyof QR]>> | undefined;
|
|
207
209
|
entityChanges: import("./types").EntityChanges<Typenames> | undefined;
|
|
208
210
|
} | {
|
|
209
211
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
210
212
|
mutationKey: keyof MP & keyof MR;
|
|
211
|
-
state: Partial<import("./types").MutationState<MP[keyof MP & keyof MR], MR[keyof MP & keyof MR]>> | undefined;
|
|
213
|
+
state: Partial<import("./types").MutationState<Typenames, MP[keyof MP & keyof MR], MR[keyof MP & keyof MR]>> | undefined;
|
|
212
214
|
entityChanges: import("./types").EntityChanges<Typenames> | undefined;
|
|
213
215
|
} | {
|
|
214
216
|
type: `@rrc/${N}/mergeEntityChanges`;
|
|
@@ -236,21 +238,21 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(partialCach
|
|
|
236
238
|
actions: {
|
|
237
239
|
/** Updates query state, and optionally merges entity changes in a single action. */
|
|
238
240
|
updateQueryStateAndEntities: {
|
|
239
|
-
<K extends keyof QP & keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryState<QP[K], QR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<Typenames> | undefined): {
|
|
241
|
+
<K extends keyof QP & keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryState<Typenames, QP[K], QR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<Typenames> | undefined): {
|
|
240
242
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
241
243
|
queryKey: K;
|
|
242
244
|
queryCacheKey: Key;
|
|
243
|
-
state: Partial<import("./types").QueryState<QP[K], QR[K]>> | undefined;
|
|
245
|
+
state: Partial<import("./types").QueryState<Typenames, QP[K], QR[K]>> | undefined;
|
|
244
246
|
entityChanges: import("./types").EntityChanges<Typenames> | undefined;
|
|
245
247
|
};
|
|
246
248
|
type: `@rrc/${N}/updateQueryStateAndEntities`;
|
|
247
249
|
};
|
|
248
250
|
/** Updates mutation state, and optionally merges entity changes in a single action. */
|
|
249
251
|
updateMutationStateAndEntities: {
|
|
250
|
-
<K extends keyof MP & keyof MR>(mutationKey: K, state?: Partial<import("./types").MutationState<MP[K], MR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<Typenames> | undefined): {
|
|
252
|
+
<K extends keyof MP & keyof MR>(mutationKey: K, state?: Partial<import("./types").MutationState<Typenames, MP[K], MR[K]>> | undefined, entityChanges?: import("./types").EntityChanges<Typenames> | undefined): {
|
|
251
253
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
252
254
|
mutationKey: K;
|
|
253
|
-
state: Partial<import("./types").MutationState<MP[K], MR[K]>> | undefined;
|
|
255
|
+
state: Partial<import("./types").MutationState<Typenames, MP[K], MR[K]>> | undefined;
|
|
254
256
|
entityChanges: import("./types").EntityChanges<Typenames> | undefined;
|
|
255
257
|
};
|
|
256
258
|
type: `@rrc/${N}/updateMutationStateAndEntities`;
|
|
@@ -315,11 +317,11 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(partialCach
|
|
|
315
317
|
/** This is a cacheStateSelector from createCache options, or default one if was not provided. */
|
|
316
318
|
selectCacheState: (state: any) => import("./types").CacheState<Typenames, QP, QR, MP, MR>;
|
|
317
319
|
/** Selects query state. */
|
|
318
|
-
selectQueryState: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => import("./types").QueryState<QK_1 extends keyof QP & keyof QR ? QP[QK_1] : never, QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>;
|
|
320
|
+
selectQueryState: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => import("./types").QueryState<Typenames, QK_1 extends keyof QP & keyof QR ? QP[QK_1] : never, QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>;
|
|
319
321
|
/** Selects query latest result. */
|
|
320
322
|
selectQueryResult: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => (QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never) | undefined;
|
|
321
323
|
/** Selects query loading state. */
|
|
322
|
-
selectQueryLoading: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) =>
|
|
324
|
+
selectQueryLoading: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => false | Promise<import("./types").NormalizedQueryResponse<Typenames, QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>>;
|
|
323
325
|
/** Selects query latest error. */
|
|
324
326
|
selectQueryError: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => Error | undefined;
|
|
325
327
|
/** Selects query latest params. */
|
|
@@ -327,11 +329,11 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(partialCach
|
|
|
327
329
|
/** Selects query latest expiresAt. */
|
|
328
330
|
selectQueryExpiresAt: <QK_1 extends keyof QP | keyof QR>(state: unknown, query: QK_1, cacheKey: Key) => number | undefined;
|
|
329
331
|
/** Selects mutation state. */
|
|
330
|
-
selectMutationState: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) => import("./types").MutationState<MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never, MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>;
|
|
332
|
+
selectMutationState: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) => import("./types").MutationState<Typenames, MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never, MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>;
|
|
331
333
|
/** Selects mutation latest result. */
|
|
332
334
|
selectMutationResult: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) => (MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never) | undefined;
|
|
333
335
|
/** Selects mutation loading state. */
|
|
334
|
-
selectMutationLoading: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) =>
|
|
336
|
+
selectMutationLoading: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) => false | Promise<import("./types").NormalizedQueryResponse<Typenames, MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>>;
|
|
335
337
|
/** Selects mutation latest error. */
|
|
336
338
|
selectMutationError: <MK_1 extends keyof MP | keyof MR>(state: unknown, mutation: MK_1) => Error | undefined;
|
|
337
339
|
/** Selects mutation latest params. */
|
|
@@ -350,13 +352,15 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(partialCach
|
|
|
350
352
|
mutate: <MK_1 extends keyof MP | keyof MR>(options: MutateOptions<N, Typenames, QP, QR, MP, MR, MK_1>) => Promise<MutationResult<MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>>;
|
|
351
353
|
};
|
|
352
354
|
/** Fetches query when params change and subscribes to query state changes (except `expiresAt` field). */
|
|
353
|
-
useQuery: <QK_1 extends keyof QP | keyof QR>(options: import("./types").UseQueryOptions<N, Typenames, QK_1, QP, QR, MP, MR>) => readonly [Omit<import("./types").QueryState<QK_1 extends keyof QP & keyof QR ? QP[QK_1] : never, QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, Typenames, QP, QR, QK_1, MP, MR>, "params" | "onlyIfExpired">> | undefined) => Promise<QueryResult<QK_1 extends infer T ? T extends QK_1 ? T extends keyof QP & keyof QR ? QR[T] : never : never : never>>];
|
|
355
|
+
useQuery: <QK_1 extends keyof QP | keyof QR>(options: import("./types").UseQueryOptions<N, Typenames, QK_1, QP, QR, MP, MR>) => readonly [Omit<import("./types").QueryState<Typenames, QK_1 extends keyof QP & keyof QR ? QP[QK_1] : never, QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, Typenames, QP, QR, QK_1, MP, MR>, "params" | "onlyIfExpired">> | undefined) => Promise<QueryResult<QK_1 extends infer T ? T extends QK_1 ? T extends keyof QP & keyof QR ? QR[T] : never : never : never>>];
|
|
354
356
|
/** Subscribes to provided mutation state and provides mutate function. */
|
|
355
|
-
useMutation: <MK_1 extends keyof MP | keyof MR>(options: Omit<MutateOptions<N, Typenames, QP, QR, MP, MR, MK_1>, "params">) => readonly [(params: MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never) => Promise<MutationResult<MK_1 extends infer T ? T extends MK_1 ? T extends keyof MP & keyof MR ? MR[T] : never : never : never>>, import("./types").MutationState<MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never, MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never>, () => boolean];
|
|
357
|
+
useMutation: <MK_1 extends keyof MP | keyof MR>(options: Omit<MutateOptions<N, Typenames, QP, QR, MP, MR, MK_1>, "params">) => readonly [(params: MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never) => Promise<MutationResult<MK_1 extends infer T ? T extends MK_1 ? T extends keyof MP & keyof MR ? MR[T] : never : never : never>>, import("./types").MutationState<Typenames, MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never, MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never>, () => boolean];
|
|
356
358
|
/** useSelector + selectEntityById. */
|
|
357
359
|
useSelectEntityById: <TN extends string>(id: Key | null | undefined, typename: TN) => object | undefined;
|
|
358
360
|
};
|
|
359
361
|
utils: {
|
|
362
|
+
/** Generates the initial state by calling a reducer. Not needed for redux — it already generates it the same way when creating the store. */
|
|
363
|
+
getInitialState: () => import("./types").CacheState<Typenames, QP, QR, MP, MR>;
|
|
360
364
|
/** Apply changes to the entities map.
|
|
361
365
|
* @returns `undefined` if nothing to change, otherwise new `EntitiesMap<T>` with applied changes. */
|
|
362
366
|
applyEntityChanges: (entities: import("./types").EntitiesMap<Typenames>, changes: import("./types").EntityChanges<Typenames>) => import("./types").EntitiesMap<Typenames> | undefined;
|
package/dist/createCache.js
CHANGED
|
@@ -58,11 +58,13 @@ const withTypenames = () => {
|
|
|
58
58
|
// actions
|
|
59
59
|
const actions = (0, createActions_1.createActions)(cache.name);
|
|
60
60
|
const { updateQueryStateAndEntities, updateMutationStateAndEntities, mergeEntityChanges, invalidateQuery, clearQueryState, clearMutationState, clearCache, } = actions;
|
|
61
|
+
// reducer
|
|
62
|
+
const reducer = (0, createCacheReducer_1.createCacheReducer)(actions, Object.keys(cache.queries), cache.options);
|
|
61
63
|
return {
|
|
62
64
|
/** Keeps all options, passed while creating the cache. */
|
|
63
65
|
cache,
|
|
64
66
|
/** Reducer of the cache, should be added to redux store. */
|
|
65
|
-
reducer
|
|
67
|
+
reducer,
|
|
66
68
|
actions: {
|
|
67
69
|
/** Updates query state, and optionally merges entity changes in a single action. */
|
|
68
70
|
updateQueryStateAndEntities,
|
|
@@ -147,6 +149,11 @@ const withTypenames = () => {
|
|
|
147
149
|
},
|
|
148
150
|
},
|
|
149
151
|
utils: {
|
|
152
|
+
/** Generates the initial state by calling a reducer. Not needed for redux — it already generates it the same way when creating the store. */
|
|
153
|
+
getInitialState: () => {
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
|
+
return reducer(undefined, utilsAndConstants_1.EMPTY_OBJECT);
|
|
156
|
+
},
|
|
150
157
|
/** Apply changes to the entities map.
|
|
151
158
|
* @returns `undefined` if nothing to change, otherwise new `EntitiesMap<T>` with applied changes. */
|
|
152
159
|
applyEntityChanges: (entities, changes) => {
|
|
@@ -13,8 +13,19 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.createCacheReducer = void 0;
|
|
15
15
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
16
|
-
const optionalQueryKeys = [
|
|
17
|
-
|
|
16
|
+
const optionalQueryKeys = [
|
|
17
|
+
'error',
|
|
18
|
+
'expiresAt',
|
|
19
|
+
'result',
|
|
20
|
+
'params',
|
|
21
|
+
'loading',
|
|
22
|
+
];
|
|
23
|
+
const optionalMutationKeys = [
|
|
24
|
+
'error',
|
|
25
|
+
'result',
|
|
26
|
+
'params',
|
|
27
|
+
'loading',
|
|
28
|
+
];
|
|
18
29
|
const createCacheReducer = (actions, queryKeys, cacheOptions) => {
|
|
19
30
|
const initialState = Object.freeze({
|
|
20
31
|
entities: Object.freeze({}),
|
|
@@ -82,9 +93,6 @@ const createCacheReducer = (actions, queryKeys, cacheOptions) => {
|
|
|
82
93
|
delete newMutationState[key];
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
|
-
if ('loading' in newMutationState && !newMutationState.loading) {
|
|
86
|
-
delete newMutationState.loading;
|
|
87
|
-
}
|
|
88
96
|
// skip if new state deep equals to the old state
|
|
89
97
|
if (deepEqual === null || deepEqual === void 0 ? void 0 : deepEqual(oldMutationState !== null && oldMutationState !== void 0 ? oldMutationState : utilsAndConstants_1.EMPTY_OBJECT, newMutationState)) {
|
|
90
98
|
newMutationState = undefined;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Cache, Key, MutationState, QueryState, Typenames } from './types';
|
|
2
2
|
export type Selectors<N extends string = string, T extends Typenames = Typenames, QP = unknown, QR = unknown, MP = unknown, MR = unknown> = ReturnType<typeof createSelectors<N, T, QP, QR, MP, MR>>;
|
|
3
3
|
export declare const createSelectors: <N extends string, T extends Typenames, QP, QR, MP, MR>(cache: Cache<N, T, QP, QR, MP, MR>) => {
|
|
4
|
-
selectQueryState: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => QueryState<QK extends keyof (QP | QR) ? QP[QK] : never, QK extends keyof (QP | QR) ? QR[QK] : never>;
|
|
4
|
+
selectQueryState: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => QueryState<T, QK extends keyof (QP | QR) ? QP[QK] : never, QK extends keyof (QP | QR) ? QR[QK] : never>;
|
|
5
5
|
selectQueryResult: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => (QK extends keyof QP & keyof QR ? QR[QK] : never) | undefined;
|
|
6
|
-
selectQueryLoading: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) =>
|
|
6
|
+
selectQueryLoading: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => false | Promise<import("./types").NormalizedQueryResponse<T, QK extends keyof QP & keyof QR ? QR[QK] : never>>;
|
|
7
7
|
selectQueryError: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => Error | undefined;
|
|
8
8
|
selectQueryParams: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => (QK extends keyof QP & keyof QR ? QP[QK] : never) | undefined;
|
|
9
9
|
selectQueryExpiresAt: <QK extends keyof (QP & QR)>(state: unknown, query: QK, cacheKey: Key) => number | undefined;
|
|
10
|
-
selectMutationState: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => MutationState<MK extends keyof (MP | MR) ? MP[MK] : never, MK extends keyof (MP | MR) ? MR[MK] : never>;
|
|
10
|
+
selectMutationState: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => MutationState<T, MK extends keyof (MP | MR) ? MP[MK] : never, MK extends keyof (MP | MR) ? MR[MK] : never>;
|
|
11
11
|
selectMutationResult: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => (MK extends keyof MP & keyof MR ? MR[MK] : never) | undefined;
|
|
12
|
-
selectMutationLoading: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) =>
|
|
12
|
+
selectMutationLoading: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => false | Promise<import("./types").NormalizedQueryResponse<T, MK extends keyof MP & keyof MR ? MR[MK] : never>>;
|
|
13
13
|
selectMutationError: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => Error | undefined;
|
|
14
14
|
selectMutationParams: <MK extends keyof (MP & MR)>(state: unknown, mutation: MK) => (MK extends keyof MP & keyof MR ? MP[MK] : never) | undefined;
|
|
15
15
|
selectEntityById: <TN extends keyof T>(state: unknown, id: Key | null | undefined, typename: TN) => T[TN] | undefined;
|
package/dist/index.js
CHANGED
|
@@ -26,9 +26,13 @@ Object.defineProperty(exports, "defaultGetCacheKey", { enumerable: true, get: fu
|
|
|
26
26
|
Object.defineProperty(exports, "FetchPolicy", { enumerable: true, get: function () { return utilsAndConstants_1.FetchPolicy; } });
|
|
27
27
|
Object.defineProperty(exports, "isEmptyObject", { enumerable: true, get: function () { return utilsAndConstants_1.isEmptyObject; } });
|
|
28
28
|
// Backlog
|
|
29
|
+
// highest
|
|
30
|
+
// generate full api docs
|
|
31
|
+
// cancel all queries / mutations
|
|
32
|
+
// selectors optional cache key
|
|
29
33
|
// ! high (1.0.0-rc.0)
|
|
30
34
|
// optimistic response
|
|
31
|
-
//
|
|
35
|
+
// features list
|
|
32
36
|
// ! medium
|
|
33
37
|
// onCancel & onAbort
|
|
34
38
|
// remove empty entities and queries from state
|
package/dist/mutate.js
CHANGED
|
@@ -30,23 +30,22 @@ const mutate = (logTag_1, store_1, cache_1, actions_1, selectors_1, mutationKey_
|
|
|
30
30
|
if (abortController !== undefined) {
|
|
31
31
|
abortController.abort();
|
|
32
32
|
}
|
|
33
|
-
else {
|
|
34
|
-
store.dispatch(updateMutationStateAndEntities(mutationKey, {
|
|
35
|
-
loading: true,
|
|
36
|
-
params,
|
|
37
|
-
result: undefined,
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
33
|
}
|
|
41
34
|
const abortController = new AbortController();
|
|
42
35
|
abortControllersOfStore[mutationKey] = abortController;
|
|
36
|
+
const mutatePromise = cache.mutations[mutationKey].mutation(
|
|
37
|
+
// @ts-expect-error fix later
|
|
38
|
+
params, store, abortController.signal);
|
|
39
|
+
store.dispatch(updateMutationStateAndEntities(mutationKey, {
|
|
40
|
+
// @ts-expect-error TODO fix types
|
|
41
|
+
loading: mutatePromise,
|
|
42
|
+
params,
|
|
43
|
+
result: undefined,
|
|
44
|
+
}));
|
|
43
45
|
let response;
|
|
44
46
|
let error;
|
|
45
|
-
const fetchFn = cache.mutations[mutationKey].mutation;
|
|
46
47
|
try {
|
|
47
|
-
response = yield
|
|
48
|
-
// @ts-expect-error fix later
|
|
49
|
-
params, store, abortController.signal);
|
|
48
|
+
response = yield mutatePromise;
|
|
50
49
|
}
|
|
51
50
|
catch (e) {
|
|
52
51
|
error = e;
|
|
@@ -64,7 +63,7 @@ const mutate = (logTag_1, store_1, cache_1, actions_1, selectors_1, mutationKey_
|
|
|
64
63
|
if (error) {
|
|
65
64
|
store.dispatch(updateMutationStateAndEntities(mutationKey, {
|
|
66
65
|
error: error,
|
|
67
|
-
loading:
|
|
66
|
+
loading: undefined,
|
|
68
67
|
}));
|
|
69
68
|
// @ts-expect-error params
|
|
70
69
|
if (!(onError === null || onError === void 0 ? void 0 : onError(error, params, store, actions, selectors))) {
|
|
@@ -80,7 +79,7 @@ const mutate = (logTag_1, store_1, cache_1, actions_1, selectors_1, mutationKey_
|
|
|
80
79
|
if (response) {
|
|
81
80
|
const newState = {
|
|
82
81
|
error: undefined,
|
|
83
|
-
loading:
|
|
82
|
+
loading: undefined,
|
|
84
83
|
result: response.result,
|
|
85
84
|
};
|
|
86
85
|
store.dispatch(updateMutationStateAndEntities(mutationKey, newState, response));
|
package/dist/query.js
CHANGED
|
@@ -10,53 +10,69 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.query = void 0;
|
|
13
|
+
const cache_1 = require("./testing/redux/cache");
|
|
13
14
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
14
15
|
const query = (logTag, store, cache, actions, selectors, queryKey, cacheKey, params, secondsToLive, onlyIfExpired, mergeResults, onCompleted, onSuccess, onError) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
-
var _a, _b, _c, _d
|
|
16
|
+
var _a, _b, _c, _d;
|
|
16
17
|
if (secondsToLive === void 0) { secondsToLive = (_a = cache.queries[queryKey].secondsToLive) !== null && _a !== void 0 ? _a : cache.globals.queries.secondsToLive; }
|
|
17
18
|
if (mergeResults === void 0) { mergeResults = cache.queries[queryKey].mergeResults; }
|
|
18
19
|
if (onCompleted === void 0) { onCompleted = cache.queries[queryKey].onCompleted; }
|
|
19
20
|
if (onSuccess === void 0) { onSuccess = cache.queries[queryKey].onSuccess; }
|
|
20
21
|
if (onError === void 0) { onError = cache.queries[queryKey].onError; }
|
|
22
|
+
const { selectQueryResult } = selectors;
|
|
21
23
|
const logsEnabled = cache.options.logsEnabled;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
+
const queryStateOnStart = (0, cache_1.selectQueryState)(store.getState(),
|
|
25
|
+
// @ts-expect-error TODO fix types
|
|
26
|
+
queryKey, cacheKey);
|
|
24
27
|
if (queryStateOnStart === null || queryStateOnStart === void 0 ? void 0 : queryStateOnStart.loading) {
|
|
25
28
|
logsEnabled &&
|
|
26
|
-
(0, utilsAndConstants_1.log)(`${logTag} cancelled: already loading`, {
|
|
29
|
+
(0, utilsAndConstants_1.log)(`${logTag} fetch cancelled: already loading`, {
|
|
27
30
|
queryStateOnStart,
|
|
28
31
|
params,
|
|
29
32
|
cacheKey,
|
|
30
33
|
});
|
|
31
|
-
|
|
34
|
+
const error = yield queryStateOnStart.loading.then(utilsAndConstants_1.NOOP).catch(catchAndReturn);
|
|
35
|
+
return error
|
|
36
|
+
? {
|
|
37
|
+
cancelled: 'loading',
|
|
38
|
+
error,
|
|
39
|
+
}
|
|
40
|
+
: {
|
|
41
|
+
cancelled: 'loading',
|
|
42
|
+
result: selectQueryResult(store.getState(), queryKey, cacheKey),
|
|
43
|
+
};
|
|
32
44
|
}
|
|
33
45
|
if (onlyIfExpired && (queryStateOnStart === null || queryStateOnStart === void 0 ? void 0 : queryStateOnStart.expiresAt) != null && queryStateOnStart.expiresAt > Date.now()) {
|
|
34
46
|
logsEnabled &&
|
|
35
|
-
(0, utilsAndConstants_1.log)(`${logTag} cancelled: not expired yet`, {
|
|
47
|
+
(0, utilsAndConstants_1.log)(`${logTag} fetch cancelled: not expired yet`, {
|
|
36
48
|
queryStateOnStart,
|
|
37
49
|
params,
|
|
38
50
|
cacheKey,
|
|
39
51
|
onlyIfExpired,
|
|
40
52
|
});
|
|
41
|
-
return
|
|
53
|
+
return {
|
|
54
|
+
cancelled: 'not-expired',
|
|
55
|
+
// @ts-expect-error TODO fix types
|
|
56
|
+
result: queryStateOnStart.result,
|
|
57
|
+
};
|
|
42
58
|
}
|
|
43
59
|
const { updateQueryStateAndEntities } = actions;
|
|
60
|
+
const fetchPromise = cache.queries[queryKey].query(
|
|
61
|
+
// @ts-expect-error fix later
|
|
62
|
+
params, store);
|
|
44
63
|
store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, {
|
|
45
|
-
loading:
|
|
64
|
+
loading: fetchPromise,
|
|
46
65
|
params,
|
|
47
66
|
}));
|
|
48
67
|
logsEnabled && (0, utilsAndConstants_1.log)(`${logTag} started`, { queryKey, params, cacheKey, queryStateOnStart, onlyIfExpired });
|
|
49
68
|
let response;
|
|
50
|
-
const fetchFn = cache.queries[queryKey].query;
|
|
51
69
|
try {
|
|
52
|
-
response = yield
|
|
53
|
-
// @ts-expect-error fix later
|
|
54
|
-
params, store);
|
|
70
|
+
response = yield fetchPromise;
|
|
55
71
|
}
|
|
56
72
|
catch (error) {
|
|
57
73
|
store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, {
|
|
58
74
|
error: error,
|
|
59
|
-
loading:
|
|
75
|
+
loading: undefined,
|
|
60
76
|
}));
|
|
61
77
|
// @ts-expect-error params
|
|
62
78
|
if (!(onError === null || onError === void 0 ? void 0 : onError(error, params, store))) {
|
|
@@ -71,12 +87,12 @@ const query = (logTag, store, cache, actions, selectors, queryKey, cacheKey, par
|
|
|
71
87
|
}
|
|
72
88
|
const newState = {
|
|
73
89
|
error: undefined,
|
|
74
|
-
loading:
|
|
90
|
+
loading: undefined,
|
|
75
91
|
expiresAt: (_d = response.expiresAt) !== null && _d !== void 0 ? _d : (secondsToLive != null ? Date.now() + secondsToLive * 1000 : undefined),
|
|
76
92
|
result: mergeResults
|
|
77
93
|
? mergeResults(
|
|
78
94
|
// @ts-expect-error fix later
|
|
79
|
-
(
|
|
95
|
+
selectQueryResult(store.getState(), queryKey, cacheKey), response, params, store, actions, selectors)
|
|
80
96
|
: response.result,
|
|
81
97
|
};
|
|
82
98
|
store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, newState, response));
|
|
@@ -92,4 +108,4 @@ const query = (logTag, store, cache, actions, selectors, queryKey, cacheKey, par
|
|
|
92
108
|
};
|
|
93
109
|
});
|
|
94
110
|
exports.query = query;
|
|
95
|
-
const
|
|
111
|
+
const catchAndReturn = (x) => x;
|
package/dist/types.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export type Globals<N extends string, T extends Typenames, QP, QR, MP, MR> = {
|
|
|
53
53
|
/** Determines when useQuery fetch triggers should start fetching. Fetch is performed if function returns true.
|
|
54
54
|
* Fetch triggers are: 1) mount 2) cache key change 3) skipFetch value change to false.
|
|
55
55
|
* @Default FetchPolicy.NoCacheOrExpired */
|
|
56
|
-
fetchPolicy: (expired: boolean, params: unknown, state: QueryState<unknown, unknown>, store: Store, selectors: Selectors<N, T, QP, QR, MP, MR>) => boolean;
|
|
56
|
+
fetchPolicy: (expired: boolean, params: unknown, state: QueryState<T, unknown, unknown>, store: Store, selectors: Selectors<N, T, QP, QR, MP, MR>) => boolean;
|
|
57
57
|
/** Disables any fetches when set to true. Triggers fetch when changed to false. @Default false */
|
|
58
58
|
skipFetch: boolean;
|
|
59
59
|
/** If set, this value updates expiresAt value of query state when query result is received. @Default undefined */
|
|
@@ -85,10 +85,10 @@ export type EntityIds<T extends Typenames> = {
|
|
|
85
85
|
export type CacheState<T extends Typenames, QP, QR, MP, MR> = {
|
|
86
86
|
entities: EntitiesMap<T>;
|
|
87
87
|
queries: {
|
|
88
|
-
[QK in keyof (QP | QR)]: Dict<QueryState<QP[QK], QR[QK]> | undefined>;
|
|
88
|
+
[QK in keyof (QP | QR)]: Dict<QueryState<T, QP[QK], QR[QK]> | undefined>;
|
|
89
89
|
};
|
|
90
90
|
mutations: {
|
|
91
|
-
[MK in keyof (MP | MR)]: MutationState<MP[MK], MR[MK]>;
|
|
91
|
+
[MK in keyof (MP | MR)]: MutationState<T, MP[MK], MR[MK]>;
|
|
92
92
|
};
|
|
93
93
|
};
|
|
94
94
|
export type QueryInfo<N extends string, T extends Typenames = Typenames, P = unknown, R = unknown, QP = unknown, QR = unknown, MP = unknown, MR = unknown> = Partial<Pick<Globals<N, T, QP, QR, MP, MR>['queries'], 'skipFetch' | 'secondsToLive'>> & {
|
|
@@ -96,7 +96,7 @@ export type QueryInfo<N extends string, T extends Typenames = Typenames, P = unk
|
|
|
96
96
|
/** Determines when useQuery fetch triggers should start fetching. Fetch is performed if function returns true.
|
|
97
97
|
* Fetch triggers are: 1) mount 2) cache key change 3) skipFetch value change to false.
|
|
98
98
|
* @Default FetchPolicy.NoCacheOrExpired */
|
|
99
|
-
fetchPolicy?: (expired: boolean, params: P, queryState: QueryState<P, R>, store: Store, selectors: Selectors<N, T, QP, QR, MP, MR>) => boolean;
|
|
99
|
+
fetchPolicy?: (expired: boolean, params: P, queryState: QueryState<T, P, R>, store: Store, selectors: Selectors<N, T, QP, QR, MP, MR>) => boolean;
|
|
100
100
|
/** Merges results before saving to the store. Default implementation is using the latest result. */
|
|
101
101
|
mergeResults?: (oldResult: R | undefined, response: NormalizedQueryResponse<T, R>, params: P | undefined, store: Store, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>) => R;
|
|
102
102
|
/**
|
|
@@ -118,7 +118,12 @@ params: P,
|
|
|
118
118
|
/** Store */
|
|
119
119
|
store: Store) => Promise<QueryResponse<R>>;
|
|
120
120
|
export type NormalizedQuery<T extends Typenames = Typenames, P = unknown, R = unknown> = (...args: Parameters<Query<P, R>>) => Promise<NormalizedQueryResponse<T, R>>;
|
|
121
|
-
export type QueryState<P, R> = MutationState<P, R> & {
|
|
121
|
+
export type QueryState<T extends Typenames, P, R> = MutationState<T, P, R> & {
|
|
122
|
+
/**
|
|
123
|
+
* Timestamp in milliseconds, after which state is considered expired.
|
|
124
|
+
* Hooks may refetch the query again when component mounts, cache key or skip option change, depending on the fetch policy.
|
|
125
|
+
* Client query calls also start making fetch if onlyIfExpired argument is truthy.
|
|
126
|
+
* */
|
|
122
127
|
expiresAt?: number;
|
|
123
128
|
};
|
|
124
129
|
export type UseQueryOptions<N extends string, T extends Typenames, QK extends keyof (QP & QR), QP, QR, MP, MR> = {
|
|
@@ -137,7 +142,8 @@ export type QueryResponse<R = unknown> = {
|
|
|
137
142
|
export type NormalizedQueryResponse<T extends Typenames = Typenames, R = unknown> = EntityChanges<T> & QueryResponse<R>;
|
|
138
143
|
export type QueryResult<R = unknown> = {
|
|
139
144
|
error?: unknown;
|
|
140
|
-
cancelled
|
|
145
|
+
/** Fetch cancelled reason. */
|
|
146
|
+
cancelled?: 'loading' | 'not-expired';
|
|
141
147
|
result?: R;
|
|
142
148
|
};
|
|
143
149
|
export type MutationInfo<N extends string, T extends Typenames = Typenames, P = unknown, R = unknown, QP = unknown, QR = unknown, MP = unknown, MR = unknown> = Pick<QueryInfo<N, T, P, R, QP, QR, MP, MR>, 'onCompleted' | 'onSuccess' | 'onError'> & {
|
|
@@ -164,9 +170,9 @@ export type MutationResult<R = unknown> = {
|
|
|
164
170
|
aborted?: true;
|
|
165
171
|
result?: R;
|
|
166
172
|
};
|
|
167
|
-
export type MutationState<P, R> = {
|
|
168
|
-
/**
|
|
169
|
-
loading?:
|
|
173
|
+
export type MutationState<T extends Typenames, P, R> = {
|
|
174
|
+
/** Set when fetch is currently in progress. */
|
|
175
|
+
loading?: Promise<NormalizedQueryResponse<T, R>>;
|
|
170
176
|
/** Result of the latest successfull response. */
|
|
171
177
|
result?: R;
|
|
172
178
|
/** Error of the latest response. */
|
package/dist/useMutation.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Actions } from './createActions';
|
|
2
2
|
import { Selectors } from './createSelectors';
|
|
3
3
|
import { Cache, Key, MutateOptions, MutationState, Store, Typenames } from './types';
|
|
4
|
-
export declare const useMutation: <N extends string, T extends Typenames, QP, QR, MP, MR, MK extends keyof (MP & MR)>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>, options: Omit<MutateOptions<N, T, QP, QR, MP, MR, MK>, "params">, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<import("./types").MutationResult<MK extends infer T_1 ? T_1 extends MK ? T_1 extends keyof MP & keyof MR ? MR[T_1] : never : never : never>>, MutationState<MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
|
4
|
+
export declare const useMutation: <N extends string, T extends Typenames, QP, QR, MP, MR, MK extends keyof (MP & MR)>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>, options: Omit<MutateOptions<N, T, QP, QR, MP, MR, MK>, "params">, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<import("./types").MutationResult<MK extends infer T_1 ? T_1 extends MK ? T_1 extends keyof MP & keyof MR ? MR[T_1] : never : never : never>>, MutationState<T, MK extends keyof MP & keyof MR ? MP[MK] : never, MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
package/dist/useMutation.js
CHANGED
|
@@ -43,9 +43,7 @@ const useMutation = (cache, actions, selectors, options, abortControllers) => {
|
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
45
|
abortController.abort();
|
|
46
|
-
store.dispatch(actions.updateMutationStateAndEntities(mutationKey, {
|
|
47
|
-
loading: false,
|
|
48
|
-
}));
|
|
46
|
+
store.dispatch(actions.updateMutationStateAndEntities(mutationKey, { loading: undefined }));
|
|
49
47
|
return true;
|
|
50
48
|
},
|
|
51
49
|
];
|
package/dist/useQuery.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Actions } from './createActions';
|
|
2
2
|
import { Selectors } from './createSelectors';
|
|
3
3
|
import { Cache, QueryOptions, QueryState, Typenames, UseQueryOptions } from './types';
|
|
4
|
-
export declare const useQuery: <N extends string, T extends Typenames, QP, QR, MP, MR, QK extends keyof (QP & QR)>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>, options: UseQueryOptions<N, T, QK, QP, QR, MP, MR>) => readonly [Omit<QueryState<QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, T, QP, QR, QK, MP, MR>, "params" | "onlyIfExpired">>) => Promise<import("./types").QueryResult<QK extends infer T_1 ? T_1 extends QK ? T_1 extends keyof QP & keyof QR ? QR[T_1] : never : never : never>>];
|
|
4
|
+
export declare const useQuery: <N extends string, T extends Typenames, QP, QR, MP, MR, QK extends keyof (QP & QR)>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>, options: UseQueryOptions<N, T, QK, QP, QR, MP, MR>) => readonly [Omit<QueryState<T, QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, T, QP, QR, QK, MP, MR>, "params" | "onlyIfExpired">>) => Promise<import("./types").QueryResult<QK extends infer T_1 ? T_1 extends QK ? T_1 extends keyof QP & keyof QR ? QR[T_1] : never : never : never>>];
|
|
5
5
|
/** Omit `expiresAt` from comparison */
|
|
6
|
-
export declare const useQuerySelectorStateComparer: <P, R>(state1: QueryState<P, R> | undefined, state2: QueryState<P, R> | undefined) => boolean;
|
|
6
|
+
export declare const useQuerySelectorStateComparer: <T extends Typenames, P, R>(state1: QueryState<T, P, R> | undefined, state2: QueryState<T, P, R> | undefined) => boolean;
|
package/dist/useQuery.js
CHANGED
|
@@ -16,9 +16,9 @@ const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
|
16
16
|
const useQuery = (cache, actions, selectors, options) => {
|
|
17
17
|
var _a, _b, _c;
|
|
18
18
|
const { query: queryKey, skipFetch = false, params, secondsToLive, fetchPolicy = (_a = cache.queries[queryKey].fetchPolicy) !== null && _a !== void 0 ? _a : cache.globals.queries.fetchPolicy, mergeResults, onCompleted, onSuccess, onError, } = options;
|
|
19
|
+
const { selectQueryState } = selectors;
|
|
19
20
|
const logsEnabled = cache.options.logsEnabled;
|
|
20
21
|
const getCacheKey = (_b = cache.queries[queryKey].getCacheKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetCacheKey);
|
|
21
|
-
const cacheStateSelector = cache.cacheStateSelector;
|
|
22
22
|
const store = cache.storeHooks.useStore();
|
|
23
23
|
// @ts-expect-error fix types later
|
|
24
24
|
const cacheKey = getCacheKey(params);
|
|
@@ -36,8 +36,7 @@ const useQuery = (cache, actions, selectors, options) => {
|
|
|
36
36
|
[store, queryKey, cacheKey]);
|
|
37
37
|
/** Query state */
|
|
38
38
|
const queryState = (_c = cache.storeHooks.useSelector((state) => {
|
|
39
|
-
|
|
40
|
-
return queryState; // TODO proper type
|
|
39
|
+
return selectQueryState(state, queryKey, cacheKey); // TODO proper type
|
|
41
40
|
}, (exports.useQuerySelectorStateComparer))) !== null && _c !== void 0 ? _c : utilsAndConstants_1.EMPTY_OBJECT;
|
|
42
41
|
(0, react_1.useEffect)(() => {
|
|
43
42
|
if (skipFetch) {
|
|
@@ -6,11 +6,12 @@ export declare const optionalUtils: {
|
|
|
6
6
|
export declare const IS_DEV: boolean;
|
|
7
7
|
export declare const EMPTY_OBJECT: Readonly<{}>;
|
|
8
8
|
export declare const EMPTY_ARRAY: readonly never[];
|
|
9
|
+
export declare const NOOP: () => void;
|
|
9
10
|
export declare const defaultGetCacheKey: <P = unknown>(params: P) => Key;
|
|
10
11
|
export declare const log: (tag: string, data?: unknown) => void;
|
|
11
12
|
export declare const FetchPolicy: {
|
|
12
13
|
/** Only if cache does not exist (result is undefined) or expired. */
|
|
13
|
-
NoCacheOrExpired: (expired: boolean,
|
|
14
|
+
NoCacheOrExpired: <T extends Typenames = Typenames, P = unknown, R = unknown>(expired: boolean, _params: P, state: QueryState<T, P, R>) => boolean;
|
|
14
15
|
/** Every fetch trigger. */
|
|
15
16
|
Always: () => boolean;
|
|
16
17
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isEmptyObject = exports.applyEntityChanges = exports.FetchPolicy = exports.log = exports.defaultGetCacheKey = exports.EMPTY_ARRAY = exports.EMPTY_OBJECT = exports.IS_DEV = exports.optionalUtils = exports.PACKAGE_SHORT_NAME = void 0;
|
|
3
|
+
exports.isEmptyObject = exports.applyEntityChanges = exports.FetchPolicy = exports.log = exports.defaultGetCacheKey = exports.NOOP = exports.EMPTY_ARRAY = exports.EMPTY_OBJECT = exports.IS_DEV = exports.optionalUtils = exports.PACKAGE_SHORT_NAME = void 0;
|
|
4
4
|
exports.PACKAGE_SHORT_NAME = 'rrc';
|
|
5
5
|
exports.optionalUtils = {
|
|
6
6
|
deepEqual: undefined,
|
|
@@ -22,6 +22,9 @@ exports.IS_DEV = (() => {
|
|
|
22
22
|
})();
|
|
23
23
|
exports.EMPTY_OBJECT = Object.freeze({});
|
|
24
24
|
exports.EMPTY_ARRAY = Object.freeze([]);
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
26
|
+
const NOOP = () => { };
|
|
27
|
+
exports.NOOP = NOOP;
|
|
25
28
|
const defaultGetCacheKey = (params) => {
|
|
26
29
|
switch (typeof params) {
|
|
27
30
|
case 'string':
|
|
@@ -40,7 +43,7 @@ const log = (tag, data) => {
|
|
|
40
43
|
exports.log = log;
|
|
41
44
|
exports.FetchPolicy = {
|
|
42
45
|
/** Only if cache does not exist (result is undefined) or expired. */
|
|
43
|
-
NoCacheOrExpired: (expired,
|
|
46
|
+
NoCacheOrExpired: (expired, _params, state) => {
|
|
44
47
|
return expired || state.result === undefined;
|
|
45
48
|
},
|
|
46
49
|
/** Every fetch trigger. */
|
package/package.json
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
"name": "react-redux-cache",
|
|
3
3
|
"author": "Alexander Danilov",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.18.0",
|
|
6
6
|
"description": "Powerful data fetching and caching library for Redux and Zustand that supports normalization.",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
9
|
"scripts": {
|
|
10
|
-
"example": "(cd example && yarn && yarn
|
|
10
|
+
"example": "(cd example && yarn && yarn dev)",
|
|
11
11
|
"clean": "rm -rf dist",
|
|
12
12
|
"lint": "yarn eslint src",
|
|
13
|
+
"lint-fix": "yarn eslint --fix src",
|
|
13
14
|
"build": "yarn clean && yarn lint && tsc && rm -rf dist/testing && rm -rf dist/__tests__",
|
|
14
15
|
"test": "node node_modules/jest/bin/jest.js",
|
|
15
16
|
"preminor-rc": "yarn build && npm version preminor --preid rc",
|