react-redux-cache 0.0.10 → 0.0.12
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 +170 -15
- package/dist/createCache.d.ts +5 -3
- package/dist/createCache.js +22 -32
- package/dist/index.d.ts +1 -3
- package/dist/index.js +3 -11
- package/dist/mutate.d.ts +2 -4
- package/dist/mutate.js +18 -26
- package/dist/query.d.ts +2 -2
- package/dist/query.js +16 -19
- package/dist/reducer.js +3 -3
- package/dist/types.d.ts +6 -36
- package/dist/useMutation.d.ts +3 -4
- package/dist/useMutation.js +13 -35
- package/dist/useQuery.d.ts +1 -7
- package/dist/useQuery.js +16 -67
- package/dist/utilsAndConstants.d.ts +5 -11
- package/dist/utilsAndConstants.js +9 -25
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# react-redux-cache
|
|
2
2
|
|
|
3
|
-
**Powerful** yet **lightweight** data fetching and caching library that supports **normalization** unlike `react-query` and `rtk-query`, while having similar interface. Built on top of `redux`.
|
|
3
|
+
**Powerful** yet **lightweight** data fetching and caching library that supports **normalization** unlike `react-query` and `rtk-query`, while having similar but very simple interface. Built on top of `redux`, fully typed and written on Typescript. Can be considered as `ApolloClient` for protocols other than `GraphQL`.
|
|
4
4
|
|
|
5
|
-
**Normalization** is the
|
|
5
|
+
**Normalization** is the best way to keep the state of the app **consistent** between different views, reduces the number of fetches and allows to show cached data when navigating, which greatly improves **user experience**.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Remains **full control** of redux state with ability to write custom selectors, actions and reducers to manage cached state.
|
|
8
8
|
|
|
9
9
|
Usage example can be found in `example/` folder and run by `npm run example` command from the root folder.
|
|
10
10
|
|
|
@@ -17,29 +17,36 @@ Usage example can be found in `example/` folder and run by `npm run example` com
|
|
|
17
17
|
- [api.ts](https://github.com/gentlee/react-redux-cache#apits)
|
|
18
18
|
- [Usage](https://github.com/gentlee/react-redux-cache#usage)
|
|
19
19
|
- [Advanced](https://github.com/gentlee/react-redux-cache#advanced)
|
|
20
|
+
- [resultSelector](https://github.com/gentlee/react-redux-cache#resultselector)
|
|
21
|
+
- [Infinite scroll pagination](https://github.com/gentlee/react-redux-cache#infinite-scroll-pagination)
|
|
20
22
|
- [redux-persist](https://github.com/gentlee/react-redux-cache#redux-persist)
|
|
23
|
+
- [FAQ](https://github.com/gentlee/react-redux-cache#faq)
|
|
24
|
+
- [What is cache key?](https://github.com/gentlee/react-redux-cache#what-is-cache-key)
|
|
21
25
|
|
|
22
26
|
### Installation
|
|
23
|
-
`react` and `redux` are peer dependencies.
|
|
27
|
+
`react`, `redux` and `react-redux` are peer dependencies.
|
|
24
28
|
```sh
|
|
25
|
-
npm add react-redux-cache react redux
|
|
29
|
+
npm add react-redux-cache react redux react-redux
|
|
26
30
|
```
|
|
27
31
|
### Initialization
|
|
28
|
-
|
|
29
|
-
All queries and mutations should be passed while initializing the cache
|
|
30
|
-
In this example we omit usage of actions and selectors.
|
|
32
|
+
The only function that needs to be imported is `createCache`, which creates fully typed reducer, hooks, actions, selectors and utils to be used in the app.
|
|
33
|
+
All typenames, queries and mutations should be passed while initializing the cache for proper typing.
|
|
31
34
|
#### cache.ts
|
|
32
35
|
```typescript
|
|
33
36
|
export const {
|
|
34
37
|
reducer,
|
|
35
|
-
hooks: {useMutation, useQuery, useSelectEntityById},
|
|
38
|
+
hooks: {useClient, useMutation, useQuery, useSelectEntityById},
|
|
39
|
+
// Actions, selectors and utils may be not used at all
|
|
40
|
+
selectors: {entitiesSelector, entitiesByTypenameSelector},
|
|
41
|
+
actions: {setQueryStateAndEntities, setMutationStateAndEntities, mergeEntityChanges},
|
|
42
|
+
utils: {applyEntityChanges},
|
|
36
43
|
} = createCache({
|
|
37
|
-
// This selector should
|
|
44
|
+
// This selector should return the cache state based on the path to its reducer.
|
|
38
45
|
cacheStateSelector: (state) => state.cache,
|
|
39
|
-
// Typenames provide a mapping of all typenames to their entity types.
|
|
46
|
+
// Typenames provide a mapping of all typenames to their entity types, which is needed for normalization.
|
|
40
47
|
// Empty objects with type casting can be used as values.
|
|
41
48
|
typenames: {
|
|
42
|
-
users: {} as User,
|
|
49
|
+
users: {} as User, // here `users` entities will have type `User`
|
|
43
50
|
banks: {} as Bank,
|
|
44
51
|
},
|
|
45
52
|
queries: {
|
|
@@ -54,6 +61,8 @@ export const {
|
|
|
54
61
|
```
|
|
55
62
|
#### store.ts
|
|
56
63
|
```typescript
|
|
64
|
+
// Create store as usual, passing the new cache reducer
|
|
65
|
+
// under the key, previously used in cacheStateSelector
|
|
57
66
|
const store = configureStore({
|
|
58
67
|
reducer: {
|
|
59
68
|
cache: reducer,
|
|
@@ -65,11 +74,16 @@ Query result should be of type `QueryResponse`, mutation result should be of typ
|
|
|
65
74
|
For normalization `normalizr` package is used in this example, but any other tool can be used if query result is of proper type.
|
|
66
75
|
Perfect implementation is when the backend already returns normalized data.
|
|
67
76
|
```typescript
|
|
77
|
+
|
|
78
|
+
// Example of query with normalization (recommended)
|
|
79
|
+
|
|
68
80
|
export const getUser = async (id: number) => {
|
|
69
81
|
const result = await ...
|
|
70
82
|
|
|
71
83
|
const normalizedResult: {
|
|
84
|
+
// result is id of the user
|
|
72
85
|
result: number
|
|
86
|
+
// entities contain all normalized objects
|
|
73
87
|
entities: {
|
|
74
88
|
users: Record<number, User>
|
|
75
89
|
banks: Record<string, Bank>
|
|
@@ -79,6 +93,15 @@ export const getUser = async (id: number) => {
|
|
|
79
93
|
return normalizedResult
|
|
80
94
|
}
|
|
81
95
|
|
|
96
|
+
// Example of query without normalization (not recommended)
|
|
97
|
+
|
|
98
|
+
export const getBank = (id: string) => {
|
|
99
|
+
const result: Bank = ...
|
|
100
|
+
return {result} // result is bank object, no entities passed
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Example of mutation with normalization
|
|
104
|
+
|
|
82
105
|
export const removeUser = async (id: number) => {
|
|
83
106
|
await ...
|
|
84
107
|
return {
|
|
@@ -93,8 +116,8 @@ export const removeUser = async (id: number) => {
|
|
|
93
116
|
export const UserScreen = () => {
|
|
94
117
|
const {id} = useParams()
|
|
95
118
|
|
|
96
|
-
// useQuery
|
|
97
|
-
// telling
|
|
119
|
+
// useQuery connects to redux state and if user with that id is already cached, fetch won't happen (with default cachePolicy 'cache-first')
|
|
120
|
+
// Infers all types from created cache, telling here that params and result are of type `number`.
|
|
98
121
|
const [{result: userId, loading, error}] = useQuery({
|
|
99
122
|
query: 'getUser',
|
|
100
123
|
params: Number(id),
|
|
@@ -104,7 +127,7 @@ export const UserScreen = () => {
|
|
|
104
127
|
mutation: 'updateUser',
|
|
105
128
|
})
|
|
106
129
|
|
|
107
|
-
// This selector is
|
|
130
|
+
// This selector is used for denormalization and returns entities with proper types - User and Bank
|
|
108
131
|
const user = useSelectEntityById(userId, 'users')
|
|
109
132
|
const bank = useSelectEntityById(user?.bankId, 'banks')
|
|
110
133
|
|
|
@@ -117,6 +140,113 @@ export const UserScreen = () => {
|
|
|
117
140
|
```
|
|
118
141
|
|
|
119
142
|
### Advanced
|
|
143
|
+
|
|
144
|
+
#### resultSelector
|
|
145
|
+
|
|
146
|
+
By default result of a query is stored under its **cache key**, but sometimes it makes sense to take result from other queries or normalized entities.
|
|
147
|
+
|
|
148
|
+
For example when single `User` entity is requested by `userId` for the first time, the entity can already be in the cache after `getUsers` query finished.
|
|
149
|
+
|
|
150
|
+
For that case `resultSelector` can be used:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
|
|
154
|
+
// createCache
|
|
155
|
+
|
|
156
|
+
... = createCache({
|
|
157
|
+
...
|
|
158
|
+
queries: {
|
|
159
|
+
...
|
|
160
|
+
getUser: {
|
|
161
|
+
query: getUser,
|
|
162
|
+
resultSelector: (state, id) => state.entities.users[id]?.id, // <-- Result is selected from cached entities
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// component
|
|
168
|
+
|
|
169
|
+
export const UserScreen = () => {
|
|
170
|
+
...
|
|
171
|
+
|
|
172
|
+
// When screen mounts for the first time, query is not fetched
|
|
173
|
+
// and cached value is returned if user entity was already in the cache
|
|
174
|
+
const [{result, loading, error}] = useQuery({
|
|
175
|
+
query: 'getUser',
|
|
176
|
+
params: userId,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
...
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Infinite scroll pagination
|
|
185
|
+
|
|
186
|
+
Here is an example of `getUsers` query configuration with pagination support. You can check full implementation in `/example` folder.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// createCache
|
|
190
|
+
|
|
191
|
+
...
|
|
192
|
+
} = createCache({
|
|
193
|
+
...
|
|
194
|
+
queries: {
|
|
195
|
+
getUsers: {
|
|
196
|
+
query: getUsers,
|
|
197
|
+
getCacheKey: () => 'all-pages', // single cache key is used for all pages
|
|
198
|
+
mergeResults: (oldResult, {result: newResult}) => {
|
|
199
|
+
if (!oldResult || newResult.page === 1) {
|
|
200
|
+
return newResult
|
|
201
|
+
}
|
|
202
|
+
if (newResult.page === oldResult.page + 1) {
|
|
203
|
+
return {
|
|
204
|
+
...newResult,
|
|
205
|
+
items: [...oldResult.items, ...newResult.items],
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return oldResult
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
...
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// Component
|
|
216
|
+
|
|
217
|
+
export const GetUsersScreen = () => {
|
|
218
|
+
const {query} = useClient()
|
|
219
|
+
|
|
220
|
+
const [{result: usersResult, loading, error}, refetch] = useQuery({
|
|
221
|
+
query: 'getUsers',
|
|
222
|
+
params: 1 // page
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
const onLoadNextPage = () => {
|
|
226
|
+
const lastLoadedPage = usersResult?.page ?? 0
|
|
227
|
+
query({
|
|
228
|
+
query: 'getUsers',
|
|
229
|
+
params: lastLoadedPage + 1,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const renderUser = (userId: number) => (
|
|
234
|
+
<UserRow key={userId} userId={userId}>
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
...
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<div>
|
|
241
|
+
{usersResult?.items.map(renderUser)}
|
|
242
|
+
<button onClick={refetch}>Refresh</button>
|
|
243
|
+
<button onClick={onLoadNextPage}>Load next page</button>
|
|
244
|
+
</div>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
|
|
120
250
|
#### redux-persist
|
|
121
251
|
|
|
122
252
|
Here is a simple `redux-persist` configuration:
|
|
@@ -138,3 +268,28 @@ const persistedReducer = persistReducer(
|
|
|
138
268
|
reducer
|
|
139
269
|
)
|
|
140
270
|
```
|
|
271
|
+
|
|
272
|
+
### FAQ
|
|
273
|
+
|
|
274
|
+
#### What is cache key?
|
|
275
|
+
|
|
276
|
+
**Cache key** is used for storing the query state and for performing a fetch when it changes. Queries with the same cache key share their state.
|
|
277
|
+
|
|
278
|
+
Default implementation for `getCacheKey` is:
|
|
279
|
+
```typescript
|
|
280
|
+
export const defaultGetCacheKey = <P = unknown>(params: P): Key => {
|
|
281
|
+
switch (typeof params) {
|
|
282
|
+
case 'string':
|
|
283
|
+
case 'symbol':
|
|
284
|
+
return params
|
|
285
|
+
case 'object':
|
|
286
|
+
return JSON.stringify(params)
|
|
287
|
+
default:
|
|
288
|
+
return String(params)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
It is recommended to override it when default implementation is not optimal or when keys in params object can be sorted in random order.
|
|
294
|
+
|
|
295
|
+
As example, can be overriden when implementing pagination.
|
package/dist/createCache.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { mergeEntityChanges, setMutationStateAndEntities, setQueryStateAndEntities } from './reducer';
|
|
2
|
-
import { Cache, EntitiesMap, Key,
|
|
2
|
+
import { Cache, EntitiesMap, Key, MutationResult, OptionalPartial, QueryOptions, QueryResult, Typenames } from './types';
|
|
3
3
|
import { useMutation } from './useMutation';
|
|
4
4
|
import { useQuery } from './useQuery';
|
|
5
|
+
import { applyEntityChanges } from './utilsAndConstants';
|
|
5
6
|
/**
|
|
6
7
|
* Creates reducer, actions and hooks for managing queries and mutations through redux cache.
|
|
7
8
|
*/
|
|
@@ -64,7 +65,6 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
|
|
|
64
65
|
mutate: <MK_1 extends keyof MP | keyof MR>(options: {
|
|
65
66
|
mutation: MK_1;
|
|
66
67
|
params: MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never;
|
|
67
|
-
cacheOptions?: MutationCacheOptions | undefined;
|
|
68
68
|
}) => Promise<MutationResult<MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>>;
|
|
69
69
|
};
|
|
70
70
|
/** Fetches query when params change and subscribes to query state. */
|
|
@@ -72,9 +72,11 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
|
|
|
72
72
|
/** Subscribes to provided mutation state and provides mutate function. */
|
|
73
73
|
useMutation: <MK_2 extends keyof MP | keyof MR>(options: {
|
|
74
74
|
mutation: MK_2;
|
|
75
|
-
cacheOptions?: MutationCacheOptions | undefined;
|
|
76
75
|
}) => readonly [(params: MK_2 extends keyof MP & keyof MR ? MP[MK_2] : never) => Promise<void>, import("./types").QueryMutationState<MK_2 extends keyof MP & keyof MR ? MP[MK_2] : never>, () => boolean];
|
|
77
76
|
/** Selects entity by id and subscribes to the changes. */
|
|
78
77
|
useSelectEntityById: <K_3 extends keyof T>(id: Key | null | undefined, typename: K_3) => T[K_3] | undefined;
|
|
79
78
|
};
|
|
79
|
+
utils: {
|
|
80
|
+
applyEntityChanges: (entities: EntitiesMap<T>, changes: import("./types").EntityChanges<T>) => EntitiesMap<T> | undefined;
|
|
81
|
+
};
|
|
80
82
|
};
|
package/dist/createCache.js
CHANGED
|
@@ -13,23 +13,17 @@ const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
|
13
13
|
* Creates reducer, actions and hooks for managing queries and mutations through redux cache.
|
|
14
14
|
*/
|
|
15
15
|
const createCache = (cache) => {
|
|
16
|
-
var _a, _b, _c, _d, _e
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
const hotReloadEnabled = Boolean(module === null || module === void 0 ? void 0 : module.hot);
|
|
16
|
+
var _a, _b, _c, _d, _e;
|
|
17
|
+
var _f, _g;
|
|
18
|
+
const abortControllers = new WeakMap();
|
|
20
19
|
// provide all optional fields
|
|
21
|
-
// and transform cacheOptions from QueryCachePolicy to QueryCacheOptions
|
|
22
20
|
(_a = cache.options) !== null && _a !== void 0 ? _a : (cache.options = {});
|
|
23
|
-
(_b = (
|
|
24
|
-
(_c = (
|
|
25
|
-
(_d =
|
|
26
|
-
(_e = cache.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (typeof queryInfo.cacheOptions === 'string') {
|
|
30
|
-
queryInfo.cacheOptions = useQuery_1.queryCacheOptionsByPolicy[queryInfo.cacheOptions];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
21
|
+
(_b = (_f = cache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_f.logsEnabled = false);
|
|
22
|
+
(_c = (_g = cache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_g.validateFunctionArguments = utilsAndConstants_1.isDev);
|
|
23
|
+
(_d = cache.queries) !== null && _d !== void 0 ? _d : (cache.queries = {});
|
|
24
|
+
(_e = cache.mutations) !== null && _e !== void 0 ? _e : (cache.mutations = {});
|
|
25
|
+
// @ts-expect-error for testing
|
|
26
|
+
cache.abortControllers = abortControllers;
|
|
33
27
|
const nonPartialCache = cache;
|
|
34
28
|
// make selectors
|
|
35
29
|
const entitiesSelector = (state) => {
|
|
@@ -64,24 +58,15 @@ const createCache = (cache) => {
|
|
|
64
58
|
return (0, react_1.useMemo)(() => {
|
|
65
59
|
const client = {
|
|
66
60
|
query: (options) => {
|
|
67
|
-
var _a
|
|
68
|
-
const { query: queryKey, params
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
: cacheOptionsOrPolicy;
|
|
74
|
-
const getParamsKey = (_b = nonPartialCache.queries[queryKey].getParamsKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetParamsKey);
|
|
75
|
-
const cacheKey = getCacheKey
|
|
76
|
-
? // @ts-expect-error fix later
|
|
77
|
-
getCacheKey(params)
|
|
78
|
-
: // @ts-expect-error fix later
|
|
79
|
-
getParamsKey(params);
|
|
80
|
-
return (0, query_1.query)('query', true, store, nonPartialCache, queryKey, cacheKey, cacheOptions, params);
|
|
61
|
+
var _a;
|
|
62
|
+
const { query: queryKey, params } = options;
|
|
63
|
+
const getCacheKey = (_a = nonPartialCache.queries[queryKey].getCacheKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetCacheKey);
|
|
64
|
+
// @ts-expect-error fix later
|
|
65
|
+
const cacheKey = getCacheKey(params);
|
|
66
|
+
return (0, query_1.query)('query', true, store, nonPartialCache, queryKey, cacheKey, params);
|
|
81
67
|
},
|
|
82
68
|
mutate: (options) => {
|
|
83
|
-
|
|
84
|
-
return (0, mutate_1.mutate)('mutate', true, store, nonPartialCache, options.mutation, (_a = options.cacheOptions) !== null && _a !== void 0 ? _a : useMutation_1.defaultMutationCacheOptions, options.params);
|
|
69
|
+
return (0, mutate_1.mutate)('mutate', true, store, nonPartialCache, options.mutation, options.params, abortControllers);
|
|
85
70
|
},
|
|
86
71
|
};
|
|
87
72
|
return client;
|
|
@@ -90,12 +75,17 @@ const createCache = (cache) => {
|
|
|
90
75
|
/** Fetches query when params change and subscribes to query state. */
|
|
91
76
|
useQuery: (options) => (0, useQuery_1.useQuery)(nonPartialCache, options),
|
|
92
77
|
/** Subscribes to provided mutation state and provides mutate function. */
|
|
93
|
-
useMutation: (options) => (0, useMutation_1.useMutation)(nonPartialCache, options),
|
|
78
|
+
useMutation: (options) => (0, useMutation_1.useMutation)(nonPartialCache, options, abortControllers),
|
|
94
79
|
/** Selects entity by id and subscribes to the changes. */
|
|
95
80
|
useSelectEntityById: (id, typename) => {
|
|
96
81
|
return (0, react_redux_1.useSelector)((state) => id == null ? undefined : nonPartialCache.cacheStateSelector(state).entities[typename][id]);
|
|
97
82
|
},
|
|
98
83
|
},
|
|
84
|
+
utils: {
|
|
85
|
+
applyEntityChanges: (entities, changes) => {
|
|
86
|
+
return (0, utilsAndConstants_1.applyEntityChanges)(entities, changes, nonPartialCache.options);
|
|
87
|
+
},
|
|
88
|
+
},
|
|
99
89
|
};
|
|
100
90
|
};
|
|
101
91
|
exports.createCache = createCache;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export { createCache } from './createCache';
|
|
2
2
|
export type { ReduxCacheState } from './reducer';
|
|
3
3
|
export * from './types';
|
|
4
|
-
export {
|
|
5
|
-
export { defaultQueryCacheOptions, queryCacheOptionsByPolicy } from './useQuery';
|
|
6
|
-
export { defaultCacheOptions, defaultGetParamsKey, defaultQueryMutationState, processEntityChanges, } from './utilsAndConstants';
|
|
4
|
+
export { defaultGetCacheKey, defaultQueryMutationState } from './utilsAndConstants';
|
package/dist/index.js
CHANGED
|
@@ -14,26 +14,18 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
17
|
+
exports.defaultQueryMutationState = exports.defaultGetCacheKey = exports.createCache = void 0;
|
|
18
18
|
var createCache_1 = require("./createCache");
|
|
19
19
|
Object.defineProperty(exports, "createCache", { enumerable: true, get: function () { return createCache_1.createCache; } });
|
|
20
20
|
__exportStar(require("./types"), exports);
|
|
21
|
-
var useMutation_1 = require("./useMutation");
|
|
22
|
-
Object.defineProperty(exports, "defaultMutationCacheOptions", { enumerable: true, get: function () { return useMutation_1.defaultMutationCacheOptions; } });
|
|
23
|
-
var useQuery_1 = require("./useQuery");
|
|
24
|
-
Object.defineProperty(exports, "defaultQueryCacheOptions", { enumerable: true, get: function () { return useQuery_1.defaultQueryCacheOptions; } });
|
|
25
|
-
Object.defineProperty(exports, "queryCacheOptionsByPolicy", { enumerable: true, get: function () { return useQuery_1.queryCacheOptionsByPolicy; } });
|
|
26
21
|
var utilsAndConstants_1 = require("./utilsAndConstants");
|
|
27
|
-
Object.defineProperty(exports, "
|
|
28
|
-
Object.defineProperty(exports, "defaultGetParamsKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetParamsKey; } });
|
|
22
|
+
Object.defineProperty(exports, "defaultGetCacheKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetCacheKey; } });
|
|
29
23
|
Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.defaultQueryMutationState; } });
|
|
30
|
-
Object.defineProperty(exports, "processEntityChanges", { enumerable: true, get: function () { return utilsAndConstants_1.processEntityChanges; } });
|
|
31
24
|
// Backlog
|
|
32
25
|
// ! high
|
|
33
|
-
// mutate
|
|
34
26
|
// cover with tests
|
|
35
|
-
// suport persist (no loading etc)
|
|
36
27
|
// ! medium
|
|
28
|
+
// allow multiple mutation with sam keys?
|
|
37
29
|
// type extractors from cache
|
|
38
30
|
// custom useStore
|
|
39
31
|
// return back deserialize selector?
|
package/dist/mutate.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { Store } from 'redux';
|
|
2
|
-
import { Cache, Key,
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const getAbortController: (store: Store, mutationKey: Key) => AbortController | undefined;
|
|
5
|
-
export declare const mutate: <T extends Typenames, QP, QR, MP, MR, MK extends keyof MP | keyof MR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, mutationKey: MK, cacheOptions: MutationCacheOptions, params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<void | MutationResult<MK extends keyof MP & keyof MR ? MR[MK] : never>>;
|
|
2
|
+
import { Cache, Key, MutationResult, Typenames } from './types';
|
|
3
|
+
export declare const mutate: <T extends Typenames, QP, QR, MP, MR, MK extends keyof MP | keyof MR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, mutationKey: MK, params: MK extends keyof MP & keyof MR ? MP[MK] : never, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => Promise<void | MutationResult<MK extends keyof MP & keyof MR ? MR[MK] : never>>;
|
package/dist/mutate.js
CHANGED
|
@@ -9,17 +9,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.mutate =
|
|
12
|
+
exports.mutate = void 0;
|
|
13
13
|
const reducer_1 = require("./reducer");
|
|
14
14
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
exports.getAbortController = getAbortController;
|
|
18
|
-
const mutate = (logTag, returnResult, store, cache, mutationKey, cacheOptions, params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
-
let abortControllersOfStore = exports.abortControllers.get(store);
|
|
15
|
+
const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortControllers) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
let abortControllersOfStore = abortControllers.get(store);
|
|
20
17
|
if (abortControllersOfStore === undefined) {
|
|
21
18
|
abortControllersOfStore = {};
|
|
22
|
-
|
|
19
|
+
abortControllers.set(store, abortControllersOfStore);
|
|
23
20
|
}
|
|
24
21
|
{
|
|
25
22
|
const abortController = abortControllersOfStore[mutationKey];
|
|
@@ -33,11 +30,10 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, cacheOptions, p
|
|
|
33
30
|
abortController.abort();
|
|
34
31
|
}
|
|
35
32
|
else {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}));
|
|
33
|
+
store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
|
|
34
|
+
loading: true,
|
|
35
|
+
result: undefined,
|
|
36
|
+
}));
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
39
|
const abortController = new AbortController();
|
|
@@ -64,23 +60,19 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, cacheOptions, p
|
|
|
64
60
|
}
|
|
65
61
|
delete abortControllersOfStore[mutationKey];
|
|
66
62
|
if (error) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
63
|
+
store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
|
|
64
|
+
error: error,
|
|
65
|
+
loading: false,
|
|
66
|
+
}));
|
|
73
67
|
return { error };
|
|
74
68
|
}
|
|
75
69
|
if (response) {
|
|
76
|
-
store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
: undefined, cacheOptions.cacheEntities ? response : undefined));
|
|
70
|
+
store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
|
|
71
|
+
error: undefined,
|
|
72
|
+
loading: false,
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
74
|
+
result: response.result,
|
|
75
|
+
}, response));
|
|
84
76
|
// @ts-expect-error fix later
|
|
85
77
|
return returnResult ? { result: response.result } : undefined;
|
|
86
78
|
}
|
package/dist/query.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Store } from 'redux';
|
|
2
|
-
import { Cache, Key,
|
|
3
|
-
export declare const query: <T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, queryKey: QK, cacheKey: Key,
|
|
2
|
+
import { Cache, Key, QueryResult, Typenames } from './types';
|
|
3
|
+
export declare const query: <T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, queryKey: QK, cacheKey: Key, params: QK extends keyof QP & keyof QR ? QP[QK] : never) => Promise<void | QueryResult<QK extends keyof QP & keyof QR ? QR[QK] : never>>;
|
package/dist/query.js
CHANGED
|
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.query = void 0;
|
|
13
13
|
const reducer_1 = require("./reducer");
|
|
14
14
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
15
|
-
const query = (logTag, returnResult, store, cache, queryKey, cacheKey,
|
|
15
|
+
const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
16
|
var _a;
|
|
17
17
|
const logsEnabled = cache.options.logsEnabled;
|
|
18
18
|
const cacheStateSelector = cache.cacheStateSelector;
|
|
@@ -28,10 +28,9 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, cacheOpti
|
|
|
28
28
|
});
|
|
29
29
|
return returnResult ? { cancelled: true } : undefined;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}));
|
|
31
|
+
store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
|
|
32
|
+
loading: true,
|
|
33
|
+
}));
|
|
35
34
|
logsEnabled && (0, utilsAndConstants_1.log)(`${logTag} started`, { queryStateOnStart, params, cacheKey });
|
|
36
35
|
let response;
|
|
37
36
|
const fetchFn = cache.queries[queryKey].query;
|
|
@@ -47,20 +46,18 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, cacheOpti
|
|
|
47
46
|
}));
|
|
48
47
|
return returnResult ? { error } : undefined;
|
|
49
48
|
}
|
|
50
|
-
const newState =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
: undefined;
|
|
63
|
-
store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, newState, cacheOptions.cacheEntities ? response : undefined));
|
|
49
|
+
const newState = {
|
|
50
|
+
error: undefined,
|
|
51
|
+
loading: false,
|
|
52
|
+
result: cacheResultSelector
|
|
53
|
+
? undefined
|
|
54
|
+
: mergeResults
|
|
55
|
+
? mergeResults(
|
|
56
|
+
// @ts-expect-error fix later
|
|
57
|
+
(_a = cacheStateSelector(store.getState()).queries[queryKey][cacheKey]) === null || _a === void 0 ? void 0 : _a.result, response, params)
|
|
58
|
+
: response.result,
|
|
59
|
+
};
|
|
60
|
+
store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, newState, response));
|
|
64
61
|
// @ts-expect-error fix types
|
|
65
62
|
return returnResult
|
|
66
63
|
? {
|
package/dist/reducer.js
CHANGED
|
@@ -28,7 +28,7 @@ const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
|
|
|
28
28
|
switch (action.type) {
|
|
29
29
|
case '@RRC/SET_QUERY_STATE_AND_ENTITIES': {
|
|
30
30
|
const { queryKey, queryCacheKey, state: queryState, entityChagnes } = action;
|
|
31
|
-
const newEntities = entityChagnes && (0, utilsAndConstants_1.
|
|
31
|
+
const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
|
|
32
32
|
if (!queryState && !newEntities) {
|
|
33
33
|
return state;
|
|
34
34
|
}
|
|
@@ -36,7 +36,7 @@ const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
|
|
|
36
36
|
}
|
|
37
37
|
case '@RRC/SET_MUTATION_STATE_AND_ENTITIES': {
|
|
38
38
|
const { mutationKey, state: mutationState, entityChagnes } = action;
|
|
39
|
-
const newEntities = entityChagnes && (0, utilsAndConstants_1.
|
|
39
|
+
const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
|
|
40
40
|
if (!mutationState && !newEntities) {
|
|
41
41
|
return state;
|
|
42
42
|
}
|
|
@@ -44,7 +44,7 @@ const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
|
|
|
44
44
|
}
|
|
45
45
|
case '@RRC/MERGE_ENTITY_CHANGES': {
|
|
46
46
|
const { changes } = action;
|
|
47
|
-
const newEntities = (0, utilsAndConstants_1.
|
|
47
|
+
const newEntities = (0, utilsAndConstants_1.applyEntityChanges)(state.entities, changes, cacheOptions);
|
|
48
48
|
return newEntities ? Object.assign(Object.assign({}, state), { entities: newEntities }) : state;
|
|
49
49
|
}
|
|
50
50
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -35,12 +35,6 @@ export type CacheOptions = {
|
|
|
35
35
|
* Default is true in dev mode.
|
|
36
36
|
* */
|
|
37
37
|
validateFunctionArguments: boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Enables validation of package hook arguments. Recommened to enable in dev/testing mode and disable in production.
|
|
40
|
-
* Should be disabled with hot reloading.
|
|
41
|
-
* Default is true in dev mode without hot reloading.
|
|
42
|
-
* */
|
|
43
|
-
validateHookArguments: boolean;
|
|
44
38
|
/**
|
|
45
39
|
* Enable console logs.
|
|
46
40
|
* Default is false.
|
|
@@ -60,12 +54,10 @@ export type Query<T extends Typenames, P, R> = (params: P) => Promise<QueryRespo
|
|
|
60
54
|
export type QueryInfo<T extends Typenames, P, R, S> = {
|
|
61
55
|
query: Query<T, P, R>;
|
|
62
56
|
/**
|
|
63
|
-
* Cache policy
|
|
64
|
-
*
|
|
65
|
-
* @param cache-first for each params key fetch is not called if cache exists.
|
|
66
|
-
* @param cache-and-fetch for each params key result is taken from cache and fetch is called.
|
|
57
|
+
* Cache policy.
|
|
58
|
+
* @default cache-first
|
|
67
59
|
*/
|
|
68
|
-
|
|
60
|
+
cachePolicy?: QueryCachePolicy;
|
|
69
61
|
/**
|
|
70
62
|
* Selector for query result from redux state.
|
|
71
63
|
* Can prevent hook from doing unnecessary fetches.
|
|
@@ -75,15 +67,9 @@ export type QueryInfo<T extends Typenames, P, R, S> = {
|
|
|
75
67
|
/** Merges results before saving to the store. */
|
|
76
68
|
mergeResults?: (oldResult: R | undefined, response: QueryResponse<T, R>, params: P | undefined) => R;
|
|
77
69
|
/**
|
|
78
|
-
*
|
|
79
|
-
* Also used as cache key, of `getCacheKey` wasn't provided.
|
|
70
|
+
* Cache key is used for storing the query state and for performing a fetch when it changes. Queries with the same cache key share their state.
|
|
80
71
|
* Default implementation uses `JSON.stringify` or `String()` depending on type.
|
|
81
|
-
*
|
|
82
|
-
getParamsKey?: (params?: P) => Key;
|
|
83
|
-
/**
|
|
84
|
-
* Cache key is a key in redux state for caching query state.
|
|
85
|
-
* Queries with equal cache keys have the same state.
|
|
86
|
-
* Default implementation is equal to `getParamsKey`.
|
|
72
|
+
* It is recommended to override it when default implementation is not optimal or when keys in params object can be sorted in random order etc.
|
|
87
73
|
* */
|
|
88
74
|
getCacheKey?: (params?: P) => Key;
|
|
89
75
|
};
|
|
@@ -91,23 +77,12 @@ export type UseQueryOptions<T extends Typenames, QP, QR, MP, MR, QK extends keyo
|
|
|
91
77
|
query: QK;
|
|
92
78
|
params: QK extends keyof (QP | QR) ? QP[QK] : never;
|
|
93
79
|
skip?: boolean;
|
|
94
|
-
} & Pick<QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReduxCacheState<T, QP, QR, MP, MR>> : never, '
|
|
80
|
+
} & Pick<QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReduxCacheState<T, QP, QR, MP, MR>> : never, 'cachePolicy' | 'mergeResults' | 'getCacheKey'>;
|
|
95
81
|
/**
|
|
96
82
|
* @param cache-first for each params key fetch is not called if cache exists.
|
|
97
83
|
* @param cache-and-fetch for each params key result is taken from cache and fetch is called.
|
|
98
84
|
*/
|
|
99
85
|
export type QueryCachePolicy = 'cache-first' | 'cache-and-fetch';
|
|
100
|
-
export type QueryCacheOptions = {
|
|
101
|
-
/**
|
|
102
|
-
* @param cache-first for each params key fetch is not called if cache exists.
|
|
103
|
-
* @param cache-and-fetch for each params key result is taken from cache and fetch is called.
|
|
104
|
-
*/
|
|
105
|
-
policy: QueryCachePolicy;
|
|
106
|
-
/** If `false`, query state is not saved in the store. Default is `true`. */
|
|
107
|
-
cacheQueryState: boolean;
|
|
108
|
-
/** If `false`, entities from response are not saved to the store. Default is `true`. */
|
|
109
|
-
cacheEntities: boolean;
|
|
110
|
-
};
|
|
111
86
|
export type QueryResponse<T extends Typenames, R> = EntityChanges<T> & {
|
|
112
87
|
/** Normalized result of a query. */
|
|
113
88
|
result: R;
|
|
@@ -123,11 +98,6 @@ export type Mutation<T extends Typenames, P, R> = (params: P,
|
|
|
123
98
|
abortSignal: AbortSignal) => Promise<MutationResponse<T, R>>;
|
|
124
99
|
export type MutationInfo<T extends Typenames, P, R> = {
|
|
125
100
|
mutation: Mutation<T, P, R>;
|
|
126
|
-
cacheOptions?: MutationCacheOptions;
|
|
127
|
-
};
|
|
128
|
-
export type MutationCacheOptions = Pick<QueryCacheOptions, 'cacheEntities'> & {
|
|
129
|
-
/** If `false`, mutation state is not saved in the store. Default is `true`. */
|
|
130
|
-
cacheMutationState: boolean;
|
|
131
101
|
};
|
|
132
102
|
export type MutationResponse<T extends Typenames, R> = EntityChanges<T> & {
|
|
133
103
|
/** Normalized result of a mutation. */
|
package/dist/useMutation.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Store } from 'redux';
|
|
2
|
+
import { Cache, Key, QueryMutationState, Typenames } from './types';
|
|
3
3
|
export declare const useMutation: <T extends Typenames, MP, MR, MK extends keyof MP | keyof MR>(cache: Cache<T, unknown, unknown, MP, MR>, options: {
|
|
4
4
|
mutation: MK;
|
|
5
|
-
|
|
6
|
-
}) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<void>, QueryMutationState<MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
|
5
|
+
}, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<void>, QueryMutationState<MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
|
package/dist/useMutation.js
CHANGED
|
@@ -9,36 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.useMutation =
|
|
12
|
+
exports.useMutation = void 0;
|
|
13
13
|
const react_1 = require("react");
|
|
14
14
|
const react_redux_1 = require("react-redux");
|
|
15
15
|
const mutate_1 = require("./mutate");
|
|
16
16
|
const reducer_1 = require("./reducer");
|
|
17
17
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
const useMutation = (cache, options) => {
|
|
23
|
-
var _a, _b;
|
|
24
|
-
const { mutation: mutationKey, cacheOptions = (_a = cache.mutations[mutationKey].cacheOptions) !== null && _a !== void 0 ? _a : exports.defaultMutationCacheOptions, } = options;
|
|
25
|
-
// Check values that should be set once.
|
|
26
|
-
// Can be removed from deps.
|
|
27
|
-
cache.options.validateHookArguments &&
|
|
28
|
-
(() => {
|
|
29
|
-
;
|
|
30
|
-
[
|
|
31
|
-
['cache', cache],
|
|
32
|
-
['cache.options', cache.options],
|
|
33
|
-
['cache.options.logsEnabled', cache.options.logsEnabled],
|
|
34
|
-
['cacheStateSelector', cache.cacheStateSelector],
|
|
35
|
-
['mutationKey', mutationKey],
|
|
36
|
-
['cacheOptions.cacheEntities', cacheOptions.cacheEntities],
|
|
37
|
-
['cacheOptions.cacheMutationState', cacheOptions.cacheMutationState],
|
|
38
|
-
]
|
|
39
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
40
|
-
.forEach((args) => (0, utilsAndConstants_1.useAssertValueNotChanged)(...args));
|
|
41
|
-
})();
|
|
18
|
+
const useMutation = (cache, options, abortControllers) => {
|
|
19
|
+
var _a;
|
|
20
|
+
const { mutation: mutationKey } = options;
|
|
42
21
|
const store = (0, react_redux_1.useStore)();
|
|
43
22
|
// Using single useMemo for performance reasons
|
|
44
23
|
const [mutationStateSelector, mutate, abort] = (0, react_1.useMemo)(() => {
|
|
@@ -54,27 +33,26 @@ const useMutation = (cache, options) => {
|
|
|
54
33
|
},
|
|
55
34
|
// mutate
|
|
56
35
|
(params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
-
yield (0, mutate_1.mutate)('useMutation.mutate', false, store, cache, mutationKey,
|
|
36
|
+
yield (0, mutate_1.mutate)('useMutation.mutate', false, store, cache, mutationKey, params, abortControllers);
|
|
58
37
|
}),
|
|
59
38
|
// abort
|
|
60
39
|
() => {
|
|
61
|
-
|
|
40
|
+
var _a;
|
|
41
|
+
const abortController = (_a = abortControllers.get(store)) === null || _a === void 0 ? void 0 : _a[mutationKey];
|
|
62
42
|
if (abortController === undefined || abortController.signal.aborted) {
|
|
63
43
|
return false;
|
|
64
44
|
}
|
|
65
45
|
abortController.abort();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}));
|
|
46
|
+
store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
|
|
47
|
+
loading: false,
|
|
48
|
+
}));
|
|
70
49
|
return true;
|
|
71
50
|
},
|
|
72
51
|
];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
[store, cacheOptions.cacheEntities, cacheOptions.cacheMutationState]);
|
|
52
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
+
}, [mutationKey, store]);
|
|
76
54
|
// @ts-expect-error fix later
|
|
77
|
-
const mutationState = (
|
|
55
|
+
const mutationState = (_a = (0, react_redux_1.useSelector)(mutationStateSelector)) !== null && _a !== void 0 ? _a : utilsAndConstants_1.defaultQueryMutationState;
|
|
78
56
|
cache.options.logsEnabled &&
|
|
79
57
|
(0, utilsAndConstants_1.log)('useMutation', {
|
|
80
58
|
options,
|
package/dist/useQuery.d.ts
CHANGED
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
import { Cache,
|
|
2
|
-
export declare const queryCacheOptionsByPolicy: Record<QueryCachePolicy, QueryCacheOptions>;
|
|
3
|
-
export declare const defaultQueryCacheOptions: {
|
|
4
|
-
readonly policy: "cache-first";
|
|
5
|
-
readonly cacheQueryState: true;
|
|
6
|
-
readonly cacheEntities: true;
|
|
7
|
-
};
|
|
1
|
+
import { Cache, QueryMutationState, Typenames, UseQueryOptions } from './types';
|
|
8
2
|
export declare const useQuery: <T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(cache: Cache<T, QP, QR, MP, MR>, options: UseQueryOptions<T, QP, QR, MP, MR, QK>) => readonly [QueryMutationState<QK extends keyof QP & keyof QR ? QR[QK] : never>, () => Promise<void>];
|
package/dist/useQuery.js
CHANGED
|
@@ -9,84 +9,34 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.useQuery =
|
|
12
|
+
exports.useQuery = void 0;
|
|
13
13
|
const react_1 = require("react");
|
|
14
14
|
const react_redux_1 = require("react-redux");
|
|
15
15
|
const query_1 = require("./query");
|
|
16
16
|
const utilsAndConstants_1 = require("./utilsAndConstants");
|
|
17
|
-
const cacheFirstOptions = {
|
|
18
|
-
policy: 'cache-first',
|
|
19
|
-
cacheQueryState: true,
|
|
20
|
-
cacheEntities: true,
|
|
21
|
-
};
|
|
22
|
-
exports.queryCacheOptionsByPolicy = {
|
|
23
|
-
'cache-first': cacheFirstOptions,
|
|
24
|
-
'cache-and-fetch': Object.assign(Object.assign({}, cacheFirstOptions), { policy: 'cache-and-fetch' }),
|
|
25
|
-
};
|
|
26
|
-
exports.defaultQueryCacheOptions = cacheFirstOptions;
|
|
27
17
|
const useQuery = (cache, options) => {
|
|
28
18
|
var _a, _b, _c;
|
|
29
|
-
const { query: queryKey, skip, params,
|
|
19
|
+
const { query: queryKey, skip, params, cachePolicy = (_a = cache.queries[queryKey].cachePolicy) !== null && _a !== void 0 ? _a : 'cache-first', getCacheKey = (_b = cache.queries[queryKey].getCacheKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetCacheKey), } = options;
|
|
30
20
|
const logsEnabled = cache.options.logsEnabled;
|
|
31
|
-
const getParamsKey = (_b = cache.queries[queryKey].getParamsKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetParamsKey);
|
|
32
21
|
const cacheResultSelector = cache.queries[queryKey].resultSelector;
|
|
33
22
|
const cacheStateSelector = cache.cacheStateSelector;
|
|
34
|
-
const cacheOptions = typeof cacheOptionsOrPolicy === 'string'
|
|
35
|
-
? exports.queryCacheOptionsByPolicy[cacheOptionsOrPolicy]
|
|
36
|
-
: cacheOptionsOrPolicy;
|
|
37
23
|
const store = (0, react_redux_1.useStore)();
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
['cache.queries', cache.queries],
|
|
46
|
-
['cacheStateSelector', cache.cacheStateSelector],
|
|
47
|
-
['cacheOptions.cacheEntities', cacheOptions.cacheEntities],
|
|
48
|
-
['cacheOptions.cacheQueryState', cacheOptions.cacheQueryState],
|
|
49
|
-
['options.query', options.query],
|
|
50
|
-
['queryKey', queryKey],
|
|
51
|
-
['resultSelector', cache.queries[queryKey].resultSelector],
|
|
52
|
-
['mergeResults', cache.queries[queryKey].mergeResults],
|
|
53
|
-
['getParamsKey', cache.queries[queryKey].getParamsKey],
|
|
54
|
-
['getCacheKey', cache.queries[queryKey].getCacheKey],
|
|
55
|
-
]
|
|
56
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
57
|
-
.forEach((args) => (0, utilsAndConstants_1.useAssertValueNotChanged)(...args));
|
|
58
|
-
})();
|
|
59
|
-
const paramsKey = getParamsKey(
|
|
60
|
-
// @ts-expect-error fix later
|
|
61
|
-
params);
|
|
62
|
-
const [cacheKey, resultSelector] = (0, react_1.useMemo)(() => {
|
|
63
|
-
return [
|
|
64
|
-
// cacheKey
|
|
65
|
-
getCacheKey
|
|
66
|
-
? // @ts-expect-error fix types later
|
|
67
|
-
getCacheKey(params)
|
|
68
|
-
: paramsKey,
|
|
69
|
-
// resultSelector
|
|
70
|
-
cacheResultSelector &&
|
|
71
|
-
((state) => cacheResultSelector(cacheStateSelector(state),
|
|
72
|
-
// @ts-expect-error fix types later
|
|
73
|
-
params)),
|
|
74
|
-
];
|
|
24
|
+
// @ts-expect-error fix types later
|
|
25
|
+
const cacheKey = getCacheKey(params);
|
|
26
|
+
const resultSelector = (0, react_1.useMemo)(() => {
|
|
27
|
+
return (cacheResultSelector &&
|
|
28
|
+
((state) => cacheResultSelector(cacheStateSelector(state),
|
|
29
|
+
// @ts-expect-error fix types later
|
|
30
|
+
params)));
|
|
75
31
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
76
|
-
}, [
|
|
32
|
+
}, [cacheKey]);
|
|
77
33
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
78
34
|
const resultFromSelector = (resultSelector && (0, react_redux_1.useSelector)(resultSelector));
|
|
79
35
|
const hasResultFromSelector = resultFromSelector !== undefined;
|
|
80
36
|
const fetch = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
-
yield (0, query_1.query)('useQuery.fetch', false, store, cache, queryKey, cacheKey,
|
|
37
|
+
yield (0, query_1.query)('useQuery.fetch', false, store, cache, queryKey, cacheKey, params);
|
|
82
38
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
|
-
}), [
|
|
84
|
-
cacheKey,
|
|
85
|
-
paramsKey,
|
|
86
|
-
cacheOptions.policy,
|
|
87
|
-
cacheOptions.cacheEntities,
|
|
88
|
-
cacheOptions.cacheQueryState,
|
|
89
|
-
]);
|
|
39
|
+
}), [store, queryKey, cacheKey]);
|
|
90
40
|
const queryStateFromSelector = (_c = (0, react_redux_1.useSelector)((state) => {
|
|
91
41
|
const queryState = cacheStateSelector(state).queries[queryKey][cacheKey];
|
|
92
42
|
return queryState; // TODO proper type
|
|
@@ -96,23 +46,22 @@ const useQuery = (cache, options) => {
|
|
|
96
46
|
: queryStateFromSelector;
|
|
97
47
|
(0, react_1.useEffect)(() => {
|
|
98
48
|
if (skip) {
|
|
99
|
-
logsEnabled && (0, utilsAndConstants_1.log)('useQuery.useEffect skip fetch', { skip,
|
|
49
|
+
logsEnabled && (0, utilsAndConstants_1.log)('useQuery.useEffect skip fetch', { skip, cacheKey });
|
|
100
50
|
return;
|
|
101
51
|
}
|
|
102
|
-
if (queryState.result != null &&
|
|
52
|
+
if (queryState.result != null && cachePolicy === 'cache-first') {
|
|
103
53
|
logsEnabled &&
|
|
104
54
|
(0, utilsAndConstants_1.log)('useQuery.useEffect don`t fetch due to cache policy', {
|
|
105
55
|
result: queryState.result,
|
|
106
|
-
|
|
56
|
+
cachePolicy,
|
|
107
57
|
});
|
|
108
58
|
return;
|
|
109
59
|
}
|
|
110
60
|
fetch();
|
|
111
61
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
|
-
}, [
|
|
62
|
+
}, [cacheKey, cachePolicy, skip]);
|
|
113
63
|
logsEnabled &&
|
|
114
64
|
(0, utilsAndConstants_1.log)('useQuery', {
|
|
115
|
-
paramsKey,
|
|
116
65
|
cacheKey,
|
|
117
66
|
options,
|
|
118
67
|
resultFromSelector,
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import { CacheOptions, EntitiesMap, EntityChanges, Typenames } from './types';
|
|
1
|
+
import { CacheOptions, EntitiesMap, EntityChanges, Key, Typenames } from './types';
|
|
2
2
|
export declare const PACKAGE_SHORT_NAME = "RRC";
|
|
3
3
|
export declare const isDev: boolean;
|
|
4
|
-
export declare const defaultCacheOptions: {
|
|
5
|
-
logsEnabled: boolean;
|
|
6
|
-
validateFunctionArguments: boolean;
|
|
7
|
-
validateHookArguments: boolean;
|
|
8
|
-
};
|
|
9
4
|
export declare const defaultQueryMutationState: {
|
|
10
5
|
readonly loading: false;
|
|
11
6
|
readonly error: undefined;
|
|
12
7
|
};
|
|
13
|
-
export declare const
|
|
14
|
-
export declare const useAssertValueNotChanged: (name: string, value: unknown) => void;
|
|
8
|
+
export declare const defaultGetCacheKey: <P = unknown>(params: P) => Key;
|
|
15
9
|
export declare const log: (tag: string, data?: unknown) => void;
|
|
16
10
|
/**
|
|
17
|
-
*
|
|
18
|
-
* @return `undefined` if nothing to change, otherwise
|
|
11
|
+
* Apply changes to the entities map.
|
|
12
|
+
* @return `undefined` if nothing to change, otherwise new entities map with applied changes.
|
|
19
13
|
*/
|
|
20
|
-
export declare const
|
|
14
|
+
export declare const applyEntityChanges: <T extends Typenames>(entities: EntitiesMap<T>, changes: EntityChanges<T>, options: CacheOptions) => EntitiesMap<T> | undefined;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const react_1 = require("react");
|
|
3
|
+
exports.applyEntityChanges = exports.log = exports.defaultGetCacheKey = exports.defaultQueryMutationState = exports.isDev = exports.PACKAGE_SHORT_NAME = void 0;
|
|
5
4
|
exports.PACKAGE_SHORT_NAME = 'RRC';
|
|
6
5
|
exports.isDev = (() => {
|
|
7
6
|
try {
|
|
@@ -12,15 +11,11 @@ exports.isDev = (() => {
|
|
|
12
11
|
return process.env.NODE_ENV === 'development';
|
|
13
12
|
}
|
|
14
13
|
})();
|
|
15
|
-
exports.defaultCacheOptions = {
|
|
16
|
-
logsEnabled: false,
|
|
17
|
-
validateFunctionArguments: true,
|
|
18
|
-
validateHookArguments: true,
|
|
19
|
-
};
|
|
20
14
|
exports.defaultQueryMutationState = { loading: false, error: undefined };
|
|
21
|
-
const
|
|
15
|
+
const defaultGetCacheKey = (params) => {
|
|
22
16
|
switch (typeof params) {
|
|
23
17
|
case 'string':
|
|
18
|
+
case 'symbol':
|
|
24
19
|
return params;
|
|
25
20
|
case 'object':
|
|
26
21
|
return JSON.stringify(params);
|
|
@@ -28,27 +23,16 @@ const defaultGetParamsKey = (params) => {
|
|
|
28
23
|
return String(params);
|
|
29
24
|
}
|
|
30
25
|
};
|
|
31
|
-
exports.
|
|
32
|
-
const useAssertValueNotChanged = (name, value) => {
|
|
33
|
-
const firstMountRef = (0, react_1.useRef)(false);
|
|
34
|
-
(0, react_1.useMemo)(() => {
|
|
35
|
-
if (firstMountRef.current) {
|
|
36
|
-
throw new Error(`${name} should not be modified`);
|
|
37
|
-
}
|
|
38
|
-
firstMountRef.current = true;
|
|
39
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
-
}, [value]);
|
|
41
|
-
};
|
|
42
|
-
exports.useAssertValueNotChanged = useAssertValueNotChanged;
|
|
26
|
+
exports.defaultGetCacheKey = defaultGetCacheKey;
|
|
43
27
|
const log = (tag, data) => {
|
|
44
28
|
console.debug(`@${exports.PACKAGE_SHORT_NAME} [${tag}]`, data);
|
|
45
29
|
};
|
|
46
30
|
exports.log = log;
|
|
47
31
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @return `undefined` if nothing to change, otherwise
|
|
32
|
+
* Apply changes to the entities map.
|
|
33
|
+
* @return `undefined` if nothing to change, otherwise new entities map with applied changes.
|
|
50
34
|
*/
|
|
51
|
-
const
|
|
35
|
+
const applyEntityChanges = (entities, changes, options) => {
|
|
52
36
|
var _a, _b, _c;
|
|
53
37
|
if (options.validateFunctionArguments) {
|
|
54
38
|
// check for merge and entities both set
|
|
@@ -99,11 +83,11 @@ const processEntityChanges = (entities, changes, options) => {
|
|
|
99
83
|
result[typename] = newEntities;
|
|
100
84
|
}
|
|
101
85
|
options.logsEnabled &&
|
|
102
|
-
(0, exports.log)('
|
|
86
|
+
(0, exports.log)('applyEntityChanges', {
|
|
103
87
|
entities,
|
|
104
88
|
changes,
|
|
105
89
|
result,
|
|
106
90
|
});
|
|
107
91
|
return result;
|
|
108
92
|
};
|
|
109
|
-
exports.
|
|
93
|
+
exports.applyEntityChanges = applyEntityChanges;
|
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.0.
|
|
5
|
+
"version": "0.0.12",
|
|
6
6
|
"description": "Powerful data fetching and caching library that supports normalization, built on top of redux",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"example": "(cd example && yarn && yarn start)",
|
|
11
11
|
"clean": "rm -rf dist",
|
|
12
|
-
"
|
|
12
|
+
"lint": "yarn eslint src",
|
|
13
|
+
"build": "yarn clean && yarn lint && tsc && yarn pack -f package.tgz",
|
|
13
14
|
"test": "node node_modules/jest/bin/jest.js",
|
|
14
15
|
"prepublishOnly": "yarn build && yarn test"
|
|
15
16
|
},
|