react-redux-cache 0.0.11 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,8 +6,6 @@
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
- Usage example can be found in `example/` folder and run by `npm run example` command from the root folder.
10
-
11
9
  ### Table of contents
12
10
 
13
11
  - [Installation](https://github.com/gentlee/react-redux-cache#Installation)
@@ -17,8 +15,12 @@ Usage example can be found in `example/` folder and run by `npm run example` com
17
15
  - [api.ts](https://github.com/gentlee/react-redux-cache#apits)
18
16
  - [Usage](https://github.com/gentlee/react-redux-cache#usage)
19
17
  - [Advanced](https://github.com/gentlee/react-redux-cache#advanced)
18
+ - [resultSelector](https://github.com/gentlee/react-redux-cache#resultselector)
20
19
  - [Infinite scroll pagination](https://github.com/gentlee/react-redux-cache#infinite-scroll-pagination)
21
20
  - [redux-persist](https://github.com/gentlee/react-redux-cache#redux-persist)
21
+ - [FAQ](https://github.com/gentlee/react-redux-cache#faq)
22
+ - [What is a query cache key?](https://github.com/gentlee/react-redux-cache#what-is-a-query-cache-key)
23
+ - [How mutation fetching differs from queries?](https://github.com/gentlee/react-redux-cache#how-mutation-fetching-differs-from-queries)
22
24
 
23
25
  ### Installation
24
26
  `react`, `redux` and `react-redux` are peer dependencies.
@@ -26,7 +28,7 @@ Usage example can be found in `example/` folder and run by `npm run example` com
26
28
  npm add react-redux-cache react redux react-redux
27
29
  ```
28
30
  ### Initialization
29
- 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.
31
+ 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. Only **single** cache reducer per store is supported currenlty.
30
32
  All typenames, queries and mutations should be passed while initializing the cache for proper typing.
31
33
  #### cache.ts
32
34
  ```typescript
@@ -35,7 +37,7 @@ export const {
35
37
  hooks: {useClient, useMutation, useQuery, useSelectEntityById},
36
38
  // Actions, selectors and utils may be not used at all
37
39
  selectors: {entitiesSelector, entitiesByTypenameSelector},
38
- actions: {setQueryStateAndEntities, setMutationStateAndEntities, mergeEntityChanges},
40
+ actions: {updateQueryStateAndEntities, updateMutationStateAndEntities, mergeEntityChanges},
39
41
  utils: {applyEntityChanges},
40
42
  } = createCache({
41
43
  // This selector should return the cache state based on the path to its reducer.
@@ -108,6 +110,9 @@ export const removeUser = async (id: number) => {
108
110
  ```
109
111
 
110
112
  ### Usage
113
+
114
+ Please check `example/` folder (`npm run example` to run).
115
+
111
116
  #### UserScreen.tsx
112
117
  ```typescript
113
118
  export const UserScreen = () => {
@@ -138,6 +143,46 @@ export const UserScreen = () => {
138
143
 
139
144
  ### Advanced
140
145
 
146
+ #### resultSelector
147
+
148
+ 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.
149
+
150
+ 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.
151
+
152
+ For that case `resultSelector` can be used:
153
+
154
+ ```typescript
155
+
156
+ // createCache
157
+
158
+ ... = createCache({
159
+ ...
160
+ queries: {
161
+ ...
162
+ getUser: {
163
+ query: getUser,
164
+ resultSelector: (state, id) => state.entities.users[id]?.id, // <-- Result is selected from cached entities
165
+ },
166
+ },
167
+ })
168
+
169
+ // component
170
+
171
+ export const UserScreen = () => {
172
+ ...
173
+
174
+ // When screen mounts for the first time, query is not fetched
175
+ // and cached value is returned if user entity was already in the cache
176
+ const [{result, loading, error}] = useQuery({
177
+ query: 'getUser',
178
+ params: userId,
179
+ })
180
+
181
+ ...
182
+ }
183
+
184
+ ```
185
+
141
186
  #### Infinite scroll pagination
142
187
 
143
188
  Here is an example of `getUsers` query configuration with pagination support. You can check full implementation in `/example` folder.
@@ -225,3 +270,34 @@ const persistedReducer = persistReducer(
225
270
  reducer
226
271
  )
227
272
  ```
273
+
274
+ ### FAQ
275
+
276
+ #### What is a query cache key?
277
+
278
+ **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.
279
+
280
+ Default implementation for `getCacheKey` is:
281
+ ```typescript
282
+ export const defaultGetCacheKey = <P = unknown>(params: P): Key => {
283
+ switch (typeof params) {
284
+ case 'string':
285
+ case 'symbol':
286
+ return params
287
+ case 'object':
288
+ return JSON.stringify(params)
289
+ default:
290
+ return String(params)
291
+ }
292
+ }
293
+ ```
294
+
295
+ It is recommended to override it when default implementation is not optimal or when keys in params object can be sorted in random order.
296
+
297
+ As example, can be overriden when implementing pagination.
298
+
299
+ #### How mutation fetching differs from queries?
300
+
301
+ **Queries:** For each cache key (= unique params by default) of each query fetch is running in parallel. If fetch is already running for specific cache key, all next fetches are cancelled until it finishes.
302
+
303
+ **Mutations:** Only one mutation can be run for each mutation key at a time. If another one called, previous is aborted.
@@ -0,0 +1,32 @@
1
+ import type { EntityChanges, Key, QueryMutationState, Typenames } from './types';
2
+ export declare const updateQueryStateAndEntities: <T extends Typenames, QR, K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryMutationState<QR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
3
+ type: `${string}UPDATE_QUERY_STATE_AND_ENTITIES`;
4
+ queryKey: K;
5
+ queryCacheKey: Key;
6
+ state: Partial<QueryMutationState<QR[K]>> | undefined;
7
+ entityChagnes: EntityChanges<T> | undefined;
8
+ };
9
+ export declare const updateMutationStateAndEntities: <T extends Typenames, MR, K extends keyof MR>(mutationKey: K, state?: Partial<QueryMutationState<MR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
10
+ type: `${string}UPDATE_MUTATION_STATE_AND_ENTITIES`;
11
+ mutationKey: K;
12
+ state: Partial<QueryMutationState<MR[K]>> | undefined;
13
+ entityChagnes: EntityChanges<T> | undefined;
14
+ };
15
+ export declare const mergeEntityChanges: <T extends Typenames>(changes: EntityChanges<T>) => {
16
+ type: `${string}MERGE_ENTITY_CHANGES`;
17
+ changes: EntityChanges<T>;
18
+ };
19
+ export declare const clearQueryState: <QR, K extends keyof QR>(queryKeys: {
20
+ key: K;
21
+ cacheKey?: Key | undefined;
22
+ }[]) => {
23
+ type: `${string}CLEAR_QUERY_STATE`;
24
+ queryKeys: {
25
+ key: K;
26
+ cacheKey?: Key | undefined;
27
+ }[];
28
+ };
29
+ export declare const clearMutationState: <MR, K extends keyof MR>(mutationKeys: K[]) => {
30
+ type: `${string}CLEAR_MUTATION_STATE`;
31
+ mutationKeys: K[];
32
+ };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clearMutationState = exports.clearQueryState = exports.mergeEntityChanges = exports.updateMutationStateAndEntities = exports.updateQueryStateAndEntities = void 0;
4
+ const utilsAndConstants_1 = require("./utilsAndConstants");
5
+ const ACTION_PREFIX = `@${utilsAndConstants_1.PACKAGE_SHORT_NAME}/`;
6
+ const updateQueryStateAndEntities = (queryKey, queryCacheKey, state, entityChagnes) => ({
7
+ type: `${ACTION_PREFIX}UPDATE_QUERY_STATE_AND_ENTITIES`,
8
+ queryKey,
9
+ queryCacheKey,
10
+ state,
11
+ entityChagnes,
12
+ });
13
+ exports.updateQueryStateAndEntities = updateQueryStateAndEntities;
14
+ const updateMutationStateAndEntities = (mutationKey, state, entityChagnes) => ({
15
+ type: `${ACTION_PREFIX}UPDATE_MUTATION_STATE_AND_ENTITIES`,
16
+ mutationKey,
17
+ state,
18
+ entityChagnes,
19
+ });
20
+ exports.updateMutationStateAndEntities = updateMutationStateAndEntities;
21
+ const mergeEntityChanges = (changes) => ({
22
+ type: `${ACTION_PREFIX}MERGE_ENTITY_CHANGES`,
23
+ changes,
24
+ });
25
+ exports.mergeEntityChanges = mergeEntityChanges;
26
+ const clearQueryState = (queryKeys) => ({
27
+ type: `${ACTION_PREFIX}CLEAR_QUERY_STATE`,
28
+ queryKeys,
29
+ });
30
+ exports.clearQueryState = clearQueryState;
31
+ const clearMutationState = (mutationKeys) => ({
32
+ type: `${ACTION_PREFIX}CLEAR_MUTATION_STATE`,
33
+ mutationKeys,
34
+ });
35
+ exports.clearMutationState = clearMutationState;
@@ -1,12 +1,12 @@
1
- import { mergeEntityChanges, setMutationStateAndEntities, setQueryStateAndEntities } from './reducer';
2
- import { Cache, EntitiesMap, Key, MutationResult, OptionalPartial, QueryOptions, QueryResult, Typenames } from './types';
1
+ import { clearMutationState, clearQueryState, mergeEntityChanges, updateMutationStateAndEntities, updateQueryStateAndEntities } from './actions';
2
+ import type { Cache, EntitiesMap, Key, MutationResult, OptionalPartial, QueryOptions, QueryResult, Typenames } from './types';
3
3
  import { useMutation } from './useMutation';
4
4
  import { useQuery } from './useQuery';
5
5
  import { applyEntityChanges } from './utilsAndConstants';
6
6
  /**
7
7
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
8
8
  */
9
- export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: OptionalPartial<Cache<T, QP, QR, MP, MR>, "queries" | "mutations" | "options">) => {
9
+ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(partialCache: OptionalPartial<Cache<T, QP, QR, MP, MR>, "queries" | "mutations" | "options">) => {
10
10
  cache: Cache<T, QP, QR, MP, MR>;
11
11
  /** Reducer of the cache, should be added to redux store. */
12
12
  reducer: (state: {
@@ -17,16 +17,25 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
17
17
  type: `${string}MERGE_ENTITY_CHANGES`;
18
18
  changes: import("./types").EntityChanges<T>;
19
19
  } | {
20
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
20
+ type: `${string}UPDATE_QUERY_STATE_AND_ENTITIES`;
21
21
  queryKey: keyof QR;
22
22
  queryCacheKey: Key;
23
23
  state: Partial<import("./types").QueryMutationState<QR[keyof QR]>> | undefined;
24
24
  entityChagnes: import("./types").EntityChanges<T> | undefined;
25
25
  } | {
26
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
26
+ type: `${string}UPDATE_MUTATION_STATE_AND_ENTITIES`;
27
27
  mutationKey: keyof MR;
28
28
  state: Partial<import("./types").QueryMutationState<MR[keyof MR]>> | undefined;
29
29
  entityChagnes: import("./types").EntityChanges<T> | undefined;
30
+ } | {
31
+ type: `${string}CLEAR_QUERY_STATE`;
32
+ queryKeys: {
33
+ key: keyof QR;
34
+ cacheKey?: Key | undefined;
35
+ }[];
36
+ } | {
37
+ type: `${string}CLEAR_MUTATION_STATE`;
38
+ mutationKeys: (keyof MR)[];
30
39
  }) => {
31
40
  entities: EntitiesMap<T>;
32
41
  queries: { [QK in keyof QR]: import("./types").Dict<import("./types").QueryMutationState<QR[QK]>>; };
@@ -34,16 +43,16 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
34
43
  };
35
44
  actions: {
36
45
  /** Updates query state, and optionally merges entity changes in a single action. */
37
- setQueryStateAndEntities: <K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryMutationState<QR[K]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
38
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
46
+ updateQueryStateAndEntities: <K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryMutationState<QR[K]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
47
+ type: `${string}UPDATE_QUERY_STATE_AND_ENTITIES`;
39
48
  queryKey: K;
40
49
  queryCacheKey: Key;
41
50
  state: Partial<import("./types").QueryMutationState<QR[K]>> | undefined;
42
51
  entityChagnes: import("./types").EntityChanges<T> | undefined;
43
52
  };
44
53
  /** Updates mutation state, and optionally merges entity changes in a single action. */
45
- setMutationStateAndEntities: <K_1 extends keyof MR>(mutationKey: K_1, state?: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
46
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
54
+ updateMutationStateAndEntities: <K_1 extends keyof MR>(mutationKey: K_1, state?: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
55
+ type: `${string}UPDATE_MUTATION_STATE_AND_ENTITIES`;
47
56
  mutationKey: K_1;
48
57
  state: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined;
49
58
  entityChagnes: import("./types").EntityChanges<T> | undefined;
@@ -53,10 +62,29 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
53
62
  type: `${string}MERGE_ENTITY_CHANGES`;
54
63
  changes: import("./types").EntityChanges<T>;
55
64
  };
65
+ /** Clear states for provided query keys and cache keys.
66
+ * If cache key for query key is not provided, the whole state for query key is cleared. */
67
+ clearQueryState: <K_2 extends keyof QR>(queryKeys: {
68
+ key: K_2;
69
+ cacheKey?: Key | undefined;
70
+ }[]) => {
71
+ type: `${string}CLEAR_QUERY_STATE`;
72
+ queryKeys: {
73
+ key: K_2;
74
+ cacheKey?: Key | undefined;
75
+ }[];
76
+ };
77
+ /** Clear states for provided mutation keys. */
78
+ clearMutationState: <K_3 extends keyof MR>(mutationKeys: K_3[]) => {
79
+ type: `${string}CLEAR_MUTATION_STATE`;
80
+ mutationKeys: K_3[];
81
+ };
56
82
  };
57
83
  selectors: {
84
+ /** Select all entities from the state. */
58
85
  entitiesSelector: (state: unknown) => EntitiesMap<T>;
59
- entitiesByTypenameSelector: <TN extends keyof T>(typename: TN) => { [K_2 in keyof T]: (state: unknown) => EntitiesMap<T>[K_2]; }[TN];
86
+ /** Select all entities of provided typename. */
87
+ entitiesByTypenameSelector: <TN extends keyof T>(typename: TN) => { [K_4 in keyof T]: (state: unknown) => EntitiesMap<T>[K_4]; }[TN];
60
88
  };
61
89
  hooks: {
62
90
  /** Returns client object with query function */
@@ -74,7 +102,7 @@ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: O
74
102
  mutation: MK_2;
75
103
  }) => 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];
76
104
  /** Selects entity by id and subscribes to the changes. */
77
- useSelectEntityById: <K_3 extends keyof T>(id: Key | null | undefined, typename: K_3) => T[K_3] | undefined;
105
+ useSelectEntityById: <K_5 extends keyof T>(id: Key | null | undefined, typename: K_5) => T[K_5] | undefined;
78
106
  };
79
107
  utils: {
80
108
  applyEntityChanges: (entities: EntitiesMap<T>, changes: import("./types").EntityChanges<T>) => EntitiesMap<T> | undefined;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCache = void 0;
4
4
  const react_1 = require("react");
5
5
  const react_redux_1 = require("react-redux");
6
+ const actions_1 = require("./actions");
6
7
  const mutate_1 = require("./mutate");
7
8
  const query_1 = require("./query");
8
9
  const reducer_1 = require("./reducer");
@@ -12,44 +13,48 @@ const utilsAndConstants_1 = require("./utilsAndConstants");
12
13
  /**
13
14
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
14
15
  */
15
- const createCache = (cache) => {
16
- var _a, _b, _c, _d, _e, _f;
17
- var _g, _h, _j;
18
- // @ts-expect-error hot
19
- const hotReloadEnabled = Boolean(module === null || module === void 0 ? void 0 : module.hot);
16
+ const createCache = (partialCache) => {
17
+ var _a, _b, _c, _d, _e;
18
+ var _f, _g;
20
19
  const abortControllers = new WeakMap();
21
20
  // provide all optional fields
22
- (_a = cache.options) !== null && _a !== void 0 ? _a : (cache.options = {});
23
- (_b = (_g = cache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_g.logsEnabled = false);
24
- (_c = (_h = cache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_h.validateFunctionArguments = utilsAndConstants_1.isDev);
25
- (_d = (_j = cache.options).validateHookArguments) !== null && _d !== void 0 ? _d : (_j.validateHookArguments = utilsAndConstants_1.isDev && !hotReloadEnabled);
26
- (_e = cache.queries) !== null && _e !== void 0 ? _e : (cache.queries = {});
27
- (_f = cache.mutations) !== null && _f !== void 0 ? _f : (cache.mutations = {});
21
+ (_a = partialCache.options) !== null && _a !== void 0 ? _a : (partialCache.options = {});
22
+ (_b = (_f = partialCache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_f.logsEnabled = false);
23
+ (_c = (_g = partialCache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_g.validateFunctionArguments = utilsAndConstants_1.IS_DEV);
24
+ (_d = partialCache.queries) !== null && _d !== void 0 ? _d : (partialCache.queries = {});
25
+ (_e = partialCache.mutations) !== null && _e !== void 0 ? _e : (partialCache.mutations = {});
28
26
  // @ts-expect-error for testing
29
- cache.abortControllers = abortControllers;
30
- const nonPartialCache = cache;
27
+ partialCache.abortControllers = abortControllers;
28
+ const cache = partialCache;
31
29
  // make selectors
32
30
  const entitiesSelector = (state) => {
33
- return nonPartialCache.cacheStateSelector(state).entities;
31
+ return cache.cacheStateSelector(state).entities;
34
32
  };
35
- const enitityMapSelectorByTypename = Object.keys(cache.typenames).reduce((result, x) => {
36
- result[x] = (state) => nonPartialCache.cacheStateSelector(state).entities[x];
33
+ const enitityMapSelectorByTypename = Object.keys(partialCache.typenames).reduce((result, x) => {
34
+ result[x] = (state) => cache.cacheStateSelector(state).entities[x];
37
35
  return result;
38
36
  }, {});
39
37
  return {
40
- cache: nonPartialCache,
38
+ cache,
41
39
  /** Reducer of the cache, should be added to redux store. */
42
- reducer: (0, reducer_1.createCacheReducer)(nonPartialCache.typenames, nonPartialCache.queries, nonPartialCache.mutations, nonPartialCache.options),
40
+ reducer: (0, reducer_1.createCacheReducer)(cache.typenames, cache.queries, cache.mutations, cache.options),
43
41
  actions: {
44
42
  /** Updates query state, and optionally merges entity changes in a single action. */
45
- setQueryStateAndEntities: reducer_1.setQueryStateAndEntities,
43
+ updateQueryStateAndEntities: actions_1.updateQueryStateAndEntities,
46
44
  /** Updates mutation state, and optionally merges entity changes in a single action. */
47
- setMutationStateAndEntities: reducer_1.setMutationStateAndEntities,
45
+ updateMutationStateAndEntities: actions_1.updateMutationStateAndEntities,
48
46
  /** Merge EntityChanges to the state. */
49
- mergeEntityChanges: reducer_1.mergeEntityChanges,
47
+ mergeEntityChanges: actions_1.mergeEntityChanges,
48
+ /** Clear states for provided query keys and cache keys.
49
+ * If cache key for query key is not provided, the whole state for query key is cleared. */
50
+ clearQueryState: actions_1.clearQueryState,
51
+ /** Clear states for provided mutation keys. */
52
+ clearMutationState: actions_1.clearMutationState,
50
53
  },
51
54
  selectors: {
55
+ /** Select all entities from the state. */
52
56
  entitiesSelector,
57
+ /** Select all entities of provided typename. */
53
58
  entitiesByTypenameSelector: (typename) => {
54
59
  return enitityMapSelectorByTypename[typename];
55
60
  },
@@ -61,33 +66,32 @@ const createCache = (cache) => {
61
66
  return (0, react_1.useMemo)(() => {
62
67
  const client = {
63
68
  query: (options) => {
64
- var _a, _b;
69
+ var _a;
65
70
  const { query: queryKey, params } = options;
66
- const getParamsKey = (_a = nonPartialCache.queries[queryKey].getParamsKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetParamsKey);
67
- const getCacheKey = (_b = nonPartialCache.queries[queryKey].getCacheKey) !== null && _b !== void 0 ? _b : getParamsKey;
71
+ const getCacheKey = (_a = cache.queries[queryKey].getCacheKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetCacheKey);
68
72
  // @ts-expect-error fix later
69
73
  const cacheKey = getCacheKey(params);
70
- return (0, query_1.query)('query', true, store, nonPartialCache, queryKey, cacheKey, params);
74
+ return (0, query_1.query)('query', true, store, cache, queryKey, cacheKey, params);
71
75
  },
72
76
  mutate: (options) => {
73
- return (0, mutate_1.mutate)('mutate', true, store, nonPartialCache, options.mutation, options.params, abortControllers);
77
+ return (0, mutate_1.mutate)('mutate', true, store, cache, options.mutation, options.params, abortControllers);
74
78
  },
75
79
  };
76
80
  return client;
77
81
  }, [store]);
78
82
  },
79
83
  /** Fetches query when params change and subscribes to query state. */
80
- useQuery: (options) => (0, useQuery_1.useQuery)(nonPartialCache, options),
84
+ useQuery: (options) => (0, useQuery_1.useQuery)(cache, options),
81
85
  /** Subscribes to provided mutation state and provides mutate function. */
82
- useMutation: (options) => (0, useMutation_1.useMutation)(nonPartialCache, options, abortControllers),
86
+ useMutation: (options) => (0, useMutation_1.useMutation)(cache, options, abortControllers),
83
87
  /** Selects entity by id and subscribes to the changes. */
84
88
  useSelectEntityById: (id, typename) => {
85
- return (0, react_redux_1.useSelector)((state) => id == null ? undefined : nonPartialCache.cacheStateSelector(state).entities[typename][id]);
89
+ return (0, react_redux_1.useSelector)((state) => id == null ? undefined : cache.cacheStateSelector(state).entities[typename][id]);
86
90
  },
87
91
  },
88
92
  utils: {
89
93
  applyEntityChanges: (entities, changes) => {
90
- return (0, utilsAndConstants_1.applyEntityChanges)(entities, changes, nonPartialCache.options);
94
+ return (0, utilsAndConstants_1.applyEntityChanges)(entities, changes, cache.options);
91
95
  },
92
96
  },
93
97
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { createCache } from './createCache';
2
2
  export type { ReduxCacheState } from './reducer';
3
3
  export * from './types';
4
- export { defaultGetParamsKey, defaultQueryMutationState } from './utilsAndConstants';
4
+ export { defaultGetCacheKey, DEFAULT_QUERY_MUTATION_STATE as defaultQueryMutationState, } from './utilsAndConstants';
package/dist/index.js CHANGED
@@ -14,51 +14,43 @@ 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.defaultQueryMutationState = exports.defaultGetParamsKey = exports.createCache = void 0;
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
21
  var utilsAndConstants_1 = require("./utilsAndConstants");
22
- Object.defineProperty(exports, "defaultGetParamsKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetParamsKey; } });
23
- Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.defaultQueryMutationState; } });
22
+ Object.defineProperty(exports, "defaultGetCacheKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetCacheKey; } });
23
+ Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE; } });
24
24
  // Backlog
25
25
  // ! high
26
+ // screenshot of redux state to README
27
+ // optimistic response
26
28
  // cover with tests
29
+ // try use skip for refreshing strategy?
30
+ // add example without normalization
31
+ // make query key / cache key difference more clear in the docs
27
32
  // ! medium
28
- // allow multiple mutation with sam keys?
33
+ // make named caches to produce named hooks, actions etc (same as slices in RTK)?
34
+ // allow multiple mutation with same keys?
29
35
  // type extractors from cache
30
36
  // custom useStore
31
37
  // return back deserialize selector?
32
- // resultSelector - return also boolean that result is full enough
38
+ // resultSelector - return also boolean that result is full enough or make cache policy as a function
33
39
  // selector for entities by typename
34
- // provide call query/mutation function to call them without hooks, but with all state updates
35
- // get typenames from schema? (useSelectDenormalized)
36
40
  // callback option on error / success?
37
- // cache policy as function? needsRefetch
38
- // add verbose debug logs
39
- // refetch queries on query / mutation success?
40
- // remove state when it finished without errors
41
- // set default options like getParams
42
- // selectors for loading state of similar query or mutation (wihout using params as key)
41
+ // refetch queries on mutation success
42
+ // remove query/mutation state when it finished without errors
43
43
  // deep equal entities while merging state
44
- // support multiple stores
45
- // add validation if entity is full enough
46
- // optimistic response
47
44
  // make error type generic
48
- // proper types, remove as, any, todo
45
+ // don't cache result if resultSelector set? throw error if mergeResult set with resultSelector?
49
46
  // ! low
50
- // make types readonly
51
- // support changing query key?
52
- // remove defaultState and keep values undefined?
53
47
  // add params to the state?
54
48
  // cancellation to queries
55
49
  // if mutation & query alrady loading - make options: last, throttle, debounce, parallel?
56
50
  // add time-to-live option, and/or time-to-refresh
57
- // add getUpdateTime option to check entities while merging
58
- // useLocalMutation - uses local component state, or make store option - redux or component state or context? 1 version: redux only
51
+ // add refresh interval for queries that are mounted
59
52
  // replace try/catch with returned error
60
53
  // support any store, not only redux
61
- // QueryInfo.defaultOptions
62
- // set options in refresh/mutate functions
63
- // multiple reducers instead of 1?
64
- // don't cache result if resultSelector set? throw error if mergeResult set with resultSelector?
54
+ // readonly types?
55
+ // proper types, remove as, any, todo
56
+ // add number of retries param?
package/dist/mutate.js CHANGED
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.mutate = void 0;
13
- const reducer_1 = require("./reducer");
13
+ const actions_1 = require("./actions");
14
14
  const utilsAndConstants_1 = require("./utilsAndConstants");
15
15
  const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortControllers) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  let abortControllersOfStore = abortControllers.get(store);
@@ -30,7 +30,7 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortCo
30
30
  abortController.abort();
31
31
  }
32
32
  else {
33
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
33
+ store.dispatch((0, actions_1.updateMutationStateAndEntities)(mutationKey, {
34
34
  loading: true,
35
35
  result: undefined,
36
36
  }));
@@ -60,14 +60,14 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortCo
60
60
  }
61
61
  delete abortControllersOfStore[mutationKey];
62
62
  if (error) {
63
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
63
+ store.dispatch((0, actions_1.updateMutationStateAndEntities)(mutationKey, {
64
64
  error: error,
65
65
  loading: false,
66
66
  }));
67
67
  return { error };
68
68
  }
69
69
  if (response) {
70
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
70
+ store.dispatch((0, actions_1.updateMutationStateAndEntities)(mutationKey, {
71
71
  error: undefined,
72
72
  loading: false,
73
73
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
package/dist/query.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { Store } from 'redux';
2
- import { Cache, Key, QueryResult, Typenames } from './types';
2
+ import type { Cache, Key, QueryResult, Typenames } from './types';
3
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
@@ -10,7 +10,7 @@ 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 reducer_1 = require("./reducer");
13
+ const actions_1 = require("./actions");
14
14
  const utilsAndConstants_1 = require("./utilsAndConstants");
15
15
  const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  var _a;
@@ -28,7 +28,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
28
28
  });
29
29
  return returnResult ? { cancelled: true } : undefined;
30
30
  }
31
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
31
+ store.dispatch((0, actions_1.updateQueryStateAndEntities)(queryKey, cacheKey, {
32
32
  loading: true,
33
33
  }));
34
34
  logsEnabled && (0, utilsAndConstants_1.log)(`${logTag} started`, { queryStateOnStart, params, cacheKey });
@@ -40,7 +40,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
40
40
  params);
41
41
  }
42
42
  catch (error) {
43
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
43
+ store.dispatch((0, actions_1.updateQueryStateAndEntities)(queryKey, cacheKey, {
44
44
  error: error,
45
45
  loading: false,
46
46
  }));
@@ -57,7 +57,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
57
57
  (_a = cacheStateSelector(store.getState()).queries[queryKey][cacheKey]) === null || _a === void 0 ? void 0 : _a.result, response, params)
58
58
  : response.result,
59
59
  };
60
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, newState, response));
60
+ store.dispatch((0, actions_1.updateQueryStateAndEntities)(queryKey, cacheKey, newState, response));
61
61
  // @ts-expect-error fix types
62
62
  return returnResult
63
63
  ? {
package/dist/reducer.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Cache, Dict, EntitiesMap, EntityChanges, Key, QueryMutationState, Typenames } from './types';
1
+ import { clearMutationState, clearQueryState, mergeEntityChanges, updateMutationStateAndEntities, updateQueryStateAndEntities } from './actions';
2
+ import type { Cache, Dict, EntitiesMap, QueryMutationState, Typenames } from './types';
2
3
  export type ReduxCacheState<T extends Typenames, QP, QR, MP, MR> = ReturnType<ReturnType<typeof createCacheReducer<T, QP, QR, MP, MR>>>;
3
4
  export declare const createCacheReducer: <T extends Typenames, QP, QR, MP, MR>(typenames: T, queries: QP & QR extends infer T_1 ? { [QK in keyof T_1]: QK extends keyof QP & keyof QR ? import("./types").QueryInfo<T, QP[QK], QR[QK], {
4
5
  entities: EntitiesMap<T>;
@@ -9,38 +10,30 @@ export declare const createCacheReducer: <T extends Typenames, QP, QR, MP, MR>(t
9
10
  queries: { [QK_1 in keyof QR]: Dict<QueryMutationState<QR[QK_1]>>; };
10
11
  mutations: { [MK in keyof MR]: QueryMutationState<MR[MK]>; };
11
12
  } | undefined, action: {
12
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
13
+ type: `${string}UPDATE_QUERY_STATE_AND_ENTITIES`;
13
14
  queryKey: keyof QR;
14
- queryCacheKey: Key;
15
+ queryCacheKey: import("./types").Key;
15
16
  state: Partial<QueryMutationState<QR[keyof QR]>> | undefined;
16
- entityChagnes: EntityChanges<T> | undefined;
17
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
17
18
  } | {
18
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
19
+ type: `${string}UPDATE_MUTATION_STATE_AND_ENTITIES`;
19
20
  mutationKey: keyof MR;
20
21
  state: Partial<QueryMutationState<MR[keyof MR]>> | undefined;
21
- entityChagnes: EntityChanges<T> | undefined;
22
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
22
23
  } | {
23
24
  type: `${string}MERGE_ENTITY_CHANGES`;
24
- changes: EntityChanges<T>;
25
+ changes: import("./types").EntityChanges<T>;
26
+ } | {
27
+ type: `${string}CLEAR_QUERY_STATE`;
28
+ queryKeys: {
29
+ key: keyof QR;
30
+ cacheKey?: import("./types").Key | undefined;
31
+ }[];
32
+ } | {
33
+ type: `${string}CLEAR_MUTATION_STATE`;
34
+ mutationKeys: (keyof MR)[];
25
35
  }) => {
26
36
  entities: EntitiesMap<T>;
27
37
  queries: { [QK_1 in keyof QR]: Dict<QueryMutationState<QR[QK_1]>>; };
28
38
  mutations: { [MK in keyof MR]: QueryMutationState<MR[MK]>; };
29
39
  };
30
- export declare const setQueryStateAndEntities: <T extends Typenames, QR, K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryMutationState<QR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
31
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
32
- queryKey: K;
33
- queryCacheKey: Key;
34
- state: Partial<QueryMutationState<QR[K]>> | undefined;
35
- entityChagnes: EntityChanges<T> | undefined;
36
- };
37
- export declare const setMutationStateAndEntities: <T extends Typenames, MR, K extends keyof MR>(mutationKey: K, state?: Partial<QueryMutationState<MR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
38
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
39
- mutationKey: K;
40
- state: Partial<QueryMutationState<MR[K]>> | undefined;
41
- entityChagnes: EntityChanges<T> | undefined;
42
- };
43
- export declare const mergeEntityChanges: <T extends Typenames>(changes: EntityChanges<T>) => {
44
- type: `${string}MERGE_ENTITY_CHANGES`;
45
- changes: EntityChanges<T>;
46
- };
package/dist/reducer.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mergeEntityChanges = exports.setMutationStateAndEntities = exports.setQueryStateAndEntities = exports.createCacheReducer = void 0;
3
+ exports.createCacheReducer = void 0;
4
4
  const utilsAndConstants_1 = require("./utilsAndConstants");
5
+ const EMPTY_QUERY_STATE = Object.freeze({});
5
6
  const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
6
7
  const entitiesMap = {};
7
8
  for (const key in typenames) {
8
- entitiesMap[key] = {};
9
+ entitiesMap[key] = EMPTY_QUERY_STATE;
9
10
  }
10
11
  const queriesMap = {};
11
12
  for (const key in queries) {
@@ -25,51 +26,72 @@ const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
25
26
  initialState,
26
27
  });
27
28
  return (state = initialState, action) => {
29
+ var _a, _b;
28
30
  switch (action.type) {
29
- case '@RRC/SET_QUERY_STATE_AND_ENTITIES': {
31
+ case '@RRC/UPDATE_QUERY_STATE_AND_ENTITIES': {
30
32
  const { queryKey, queryCacheKey, state: queryState, entityChagnes } = action;
31
33
  const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
32
34
  if (!queryState && !newEntities) {
33
35
  return state;
34
36
  }
35
- return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { queries: Object.assign(Object.assign({}, state.queries), { [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), { [queryCacheKey]: Object.assign(Object.assign({}, state.queries[queryKey][queryCacheKey]), queryState) }) }) });
37
+ return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { queries: Object.assign(Object.assign({}, state.queries), { [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), { [queryCacheKey]: Object.assign(Object.assign({}, ((_a = state.queries[queryKey][queryCacheKey]) !== null && _a !== void 0 ? _a : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE)), queryState) }) }) });
36
38
  }
37
- case '@RRC/SET_MUTATION_STATE_AND_ENTITIES': {
39
+ case '@RRC/UPDATE_MUTATION_STATE_AND_ENTITIES': {
38
40
  const { mutationKey, state: mutationState, entityChagnes } = action;
39
41
  const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
40
42
  if (!mutationState && !newEntities) {
41
43
  return state;
42
44
  }
43
- return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { mutations: Object.assign(Object.assign({}, state.mutations), { [mutationKey]: Object.assign(Object.assign({}, state.mutations[mutationKey]), mutationState) }) });
45
+ return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { mutations: Object.assign(Object.assign({}, state.mutations), { [mutationKey]: Object.assign(Object.assign({}, ((_b = state.mutations[mutationKey]) !== null && _b !== void 0 ? _b : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE)), mutationState) }) });
44
46
  }
45
47
  case '@RRC/MERGE_ENTITY_CHANGES': {
46
48
  const { changes } = action;
47
49
  const newEntities = (0, utilsAndConstants_1.applyEntityChanges)(state.entities, changes, cacheOptions);
48
50
  return newEntities ? Object.assign(Object.assign({}, state), { entities: newEntities }) : state;
49
51
  }
52
+ case '@RRC/CLEAR_QUERY_STATE': {
53
+ const { queryKeys } = action;
54
+ if (!queryKeys.length) {
55
+ return state;
56
+ }
57
+ let newQueries = undefined;
58
+ for (const query of queryKeys) {
59
+ if (query.cacheKey != null) {
60
+ if ((newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[query.key][query.cacheKey]) {
61
+ newQueries !== null && newQueries !== void 0 ? newQueries : (newQueries = Object.assign({}, state.queries));
62
+ newQueries[query.key] = Object.assign({}, newQueries[query.key]);
63
+ delete newQueries[query.key][query.cacheKey];
64
+ }
65
+ }
66
+ else if ((newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[query.key] !== EMPTY_QUERY_STATE) {
67
+ newQueries !== null && newQueries !== void 0 ? newQueries : (newQueries = Object.assign({}, state.queries));
68
+ newQueries[query.key] = EMPTY_QUERY_STATE;
69
+ }
70
+ }
71
+ if (!newQueries) {
72
+ return state;
73
+ }
74
+ return Object.assign(Object.assign({}, state), { queries: newQueries });
75
+ }
76
+ case '@RRC/CLEAR_MUTATION_STATE': {
77
+ const { mutationKeys } = action;
78
+ if (!mutationKeys.length) {
79
+ return state;
80
+ }
81
+ let newMutations = undefined;
82
+ for (const mutation of mutationKeys) {
83
+ if (state.mutations[mutation]) {
84
+ newMutations !== null && newMutations !== void 0 ? newMutations : (newMutations = Object.assign({}, state.mutations));
85
+ delete newMutations[mutation];
86
+ }
87
+ }
88
+ if (!newMutations) {
89
+ return state;
90
+ }
91
+ return Object.assign(Object.assign({}, state), { mutations: newMutations });
92
+ }
50
93
  }
51
94
  return state;
52
95
  };
53
96
  };
54
97
  exports.createCacheReducer = createCacheReducer;
55
- const actionPrefix = `@${utilsAndConstants_1.PACKAGE_SHORT_NAME}/`;
56
- const setQueryStateAndEntities = (queryKey, queryCacheKey, state, entityChagnes) => ({
57
- type: `${actionPrefix}SET_QUERY_STATE_AND_ENTITIES`,
58
- queryKey,
59
- queryCacheKey,
60
- state,
61
- entityChagnes,
62
- });
63
- exports.setQueryStateAndEntities = setQueryStateAndEntities;
64
- const setMutationStateAndEntities = (mutationKey, state, entityChagnes) => ({
65
- type: `${actionPrefix}SET_MUTATION_STATE_AND_ENTITIES`,
66
- mutationKey,
67
- state,
68
- entityChagnes,
69
- });
70
- exports.setMutationStateAndEntities = setMutationStateAndEntities;
71
- const mergeEntityChanges = (changes) => ({
72
- type: `${actionPrefix}MERGE_ENTITY_CHANGES`,
73
- changes,
74
- });
75
- exports.mergeEntityChanges = mergeEntityChanges;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { createCacheReducer, ReduxCacheState } from './reducer';
1
+ import { createCacheReducer, ReduxCacheState } from './reducer';
2
2
  export type Key = string | number | symbol;
3
3
  export type Dict<T> = Record<Key, T>;
4
4
  export type OptionalPartial<T, K extends keyof T> = Partial<{
@@ -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.
@@ -73,15 +67,9 @@ export type QueryInfo<T extends Typenames, P, R, S> = {
73
67
  /** Merges results before saving to the store. */
74
68
  mergeResults?: (oldResult: R | undefined, response: QueryResponse<T, R>, params: P | undefined) => R;
75
69
  /**
76
- * Params key is used for determining if parameters were changed and fetch is needed.
77
- * 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.
78
71
  * Default implementation uses `JSON.stringify` or `String()` depending on type.
79
- * */
80
- getParamsKey?: (params?: P) => Key;
81
- /**
82
- * Cache key is a key in redux state for caching query state.
83
- * Queries with equal cache keys have the same state.
84
- * 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.
85
73
  * */
86
74
  getCacheKey?: (params?: P) => Key;
87
75
  };
@@ -12,27 +12,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.useMutation = void 0;
13
13
  const react_1 = require("react");
14
14
  const react_redux_1 = require("react-redux");
15
+ const actions_1 = require("./actions");
15
16
  const mutate_1 = require("./mutate");
16
- const reducer_1 = require("./reducer");
17
17
  const utilsAndConstants_1 = require("./utilsAndConstants");
18
18
  const useMutation = (cache, options, abortControllers) => {
19
19
  var _a;
20
20
  const { mutation: mutationKey } = options;
21
- // Check values that should be set once.
22
- // Can be removed from deps.
23
- cache.options.validateHookArguments &&
24
- (() => {
25
- ;
26
- [
27
- ['cache', cache],
28
- ['cache.options', cache.options],
29
- ['cache.options.logsEnabled', cache.options.logsEnabled],
30
- ['cacheStateSelector', cache.cacheStateSelector],
31
- ['mutationKey', mutationKey],
32
- ]
33
- // eslint-disable-next-line react-hooks/rules-of-hooks
34
- .forEach((args) => (0, utilsAndConstants_1.useAssertValueNotChanged)(...args));
35
- })();
36
21
  const store = (0, react_redux_1.useStore)();
37
22
  // Using single useMemo for performance reasons
38
23
  const [mutationStateSelector, mutate, abort] = (0, react_1.useMemo)(() => {
@@ -58,17 +43,16 @@ const useMutation = (cache, options, abortControllers) => {
58
43
  return false;
59
44
  }
60
45
  abortController.abort();
61
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
46
+ store.dispatch((0, actions_1.updateMutationStateAndEntities)(mutationKey, {
62
47
  loading: false,
63
48
  }));
64
49
  return true;
65
50
  },
66
51
  ];
67
- },
68
- // eslint-disable-next-line react-hooks/exhaustive-deps
69
- [store]);
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
53
+ }, [mutationKey, store]);
70
54
  // @ts-expect-error fix later
71
- const mutationState = (_a = (0, react_redux_1.useSelector)(mutationStateSelector)) !== null && _a !== void 0 ? _a : utilsAndConstants_1.defaultQueryMutationState;
55
+ const mutationState = (_a = (0, react_redux_1.useSelector)(mutationStateSelector)) !== null && _a !== void 0 ? _a : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE;
72
56
  cache.options.logsEnabled &&
73
57
  (0, utilsAndConstants_1.log)('useMutation', {
74
58
  options,
package/dist/useQuery.js CHANGED
@@ -16,66 +16,37 @@ const query_1 = require("./query");
16
16
  const utilsAndConstants_1 = require("./utilsAndConstants");
17
17
  const useQuery = (cache, options) => {
18
18
  var _a, _b, _c;
19
- const { query: queryKey, skip, params, cachePolicy = (_a = cache.queries[queryKey].cachePolicy) !== null && _a !== void 0 ? _a : 'cache-first', getCacheKey = cache.queries[queryKey].getCacheKey, } = options;
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;
20
20
  const logsEnabled = cache.options.logsEnabled;
21
- const getParamsKey = (_b = cache.queries[queryKey].getParamsKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetParamsKey);
22
21
  const cacheResultSelector = cache.queries[queryKey].resultSelector;
23
22
  const cacheStateSelector = cache.cacheStateSelector;
24
23
  const store = (0, react_redux_1.useStore)();
25
- // Check values that should be set once.
26
- cache.options.validateHookArguments &&
27
- (() => {
28
- ;
29
- [
30
- ['store', store],
31
- ['cache', cache],
32
- ['cache.queries', cache.queries],
33
- ['cacheStateSelector', cache.cacheStateSelector],
34
- ['options.query', options.query],
35
- ['queryKey', queryKey],
36
- ['resultSelector', cache.queries[queryKey].resultSelector],
37
- ['mergeResults', cache.queries[queryKey].mergeResults],
38
- ['getParamsKey', cache.queries[queryKey].getParamsKey],
39
- ['getCacheKey', cache.queries[queryKey].getCacheKey],
40
- ]
41
- // eslint-disable-next-line react-hooks/rules-of-hooks
42
- .forEach((args) => (0, utilsAndConstants_1.useAssertValueNotChanged)(...args));
43
- })();
44
- const paramsKey = getParamsKey(
45
- // @ts-expect-error fix later
46
- params);
47
- const [cacheKey, resultSelector] = (0, react_1.useMemo)(() => {
48
- return [
49
- // cacheKey
50
- getCacheKey
51
- ? // @ts-expect-error fix types later
52
- getCacheKey(params)
53
- : paramsKey,
54
- // resultSelector
55
- cacheResultSelector &&
56
- ((state) => cacheResultSelector(cacheStateSelector(state),
57
- // @ts-expect-error fix types later
58
- params)),
59
- ];
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)));
60
31
  // eslint-disable-next-line react-hooks/exhaustive-deps
61
- }, [paramsKey]);
32
+ }, [cacheKey]);
62
33
  // eslint-disable-next-line react-hooks/rules-of-hooks
63
34
  const resultFromSelector = (resultSelector && (0, react_redux_1.useSelector)(resultSelector));
64
35
  const hasResultFromSelector = resultFromSelector !== undefined;
65
36
  const fetch = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
66
37
  yield (0, query_1.query)('useQuery.fetch', false, store, cache, queryKey, cacheKey, params);
67
38
  // eslint-disable-next-line react-hooks/exhaustive-deps
68
- }), [cacheKey, paramsKey]);
39
+ }), [store, queryKey, cacheKey]);
69
40
  const queryStateFromSelector = (_c = (0, react_redux_1.useSelector)((state) => {
70
41
  const queryState = cacheStateSelector(state).queries[queryKey][cacheKey];
71
42
  return queryState; // TODO proper type
72
- })) !== null && _c !== void 0 ? _c : utilsAndConstants_1.defaultQueryMutationState;
43
+ })) !== null && _c !== void 0 ? _c : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE;
73
44
  const queryState = hasResultFromSelector
74
45
  ? (Object.assign(Object.assign({}, queryStateFromSelector), { result: resultFromSelector }))
75
46
  : queryStateFromSelector;
76
47
  (0, react_1.useEffect)(() => {
77
48
  if (skip) {
78
- logsEnabled && (0, utilsAndConstants_1.log)('useQuery.useEffect skip fetch', { skip, paramsKey });
49
+ logsEnabled && (0, utilsAndConstants_1.log)('useQuery.useEffect skip fetch', { skip, cacheKey });
79
50
  return;
80
51
  }
81
52
  if (queryState.result != null && cachePolicy === 'cache-first') {
@@ -88,10 +59,9 @@ const useQuery = (cache, options) => {
88
59
  }
89
60
  fetch();
90
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
91
- }, [paramsKey, cachePolicy, skip]);
62
+ }, [cacheKey, cachePolicy, skip]);
92
63
  logsEnabled &&
93
64
  (0, utilsAndConstants_1.log)('useQuery', {
94
- paramsKey,
95
65
  cacheKey,
96
66
  options,
97
67
  resultFromSelector,
@@ -1,12 +1,11 @@
1
- import { CacheOptions, EntitiesMap, EntityChanges, Typenames } from './types';
1
+ import type { CacheOptions, EntitiesMap, EntityChanges, Key, Typenames } from './types';
2
2
  export declare const PACKAGE_SHORT_NAME = "RRC";
3
- export declare const isDev: boolean;
4
- export declare const defaultQueryMutationState: {
3
+ export declare const IS_DEV: boolean;
4
+ export declare const DEFAULT_QUERY_MUTATION_STATE: {
5
5
  readonly loading: false;
6
6
  readonly error: undefined;
7
7
  };
8
- export declare const defaultGetParamsKey: <P = unknown>(params: P) => string;
9
- export declare const useAssertValueNotChanged: (name: string, value: unknown) => void;
8
+ export declare const defaultGetCacheKey: <P = unknown>(params: P) => Key;
10
9
  export declare const log: (tag: string, data?: unknown) => void;
11
10
  /**
12
11
  * Apply changes to the entities map.
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyEntityChanges = exports.log = exports.useAssertValueNotChanged = exports.defaultGetParamsKey = exports.defaultQueryMutationState = exports.isDev = exports.PACKAGE_SHORT_NAME = void 0;
4
- const react_1 = require("react");
3
+ exports.applyEntityChanges = exports.log = exports.defaultGetCacheKey = exports.DEFAULT_QUERY_MUTATION_STATE = exports.IS_DEV = exports.PACKAGE_SHORT_NAME = void 0;
5
4
  exports.PACKAGE_SHORT_NAME = 'RRC';
6
- exports.isDev = (() => {
5
+ exports.IS_DEV = (() => {
7
6
  try {
8
7
  // @ts-expect-error __DEV__ is only for React Native
9
8
  return __DEV__;
@@ -12,10 +11,11 @@ exports.isDev = (() => {
12
11
  return process.env.NODE_ENV === 'development';
13
12
  }
14
13
  })();
15
- exports.defaultQueryMutationState = { loading: false, error: undefined };
16
- const defaultGetParamsKey = (params) => {
14
+ exports.DEFAULT_QUERY_MUTATION_STATE = { loading: false, error: undefined };
15
+ const defaultGetCacheKey = (params) => {
17
16
  switch (typeof params) {
18
17
  case 'string':
18
+ case 'symbol':
19
19
  return params;
20
20
  case 'object':
21
21
  return JSON.stringify(params);
@@ -23,18 +23,7 @@ const defaultGetParamsKey = (params) => {
23
23
  return String(params);
24
24
  }
25
25
  };
26
- exports.defaultGetParamsKey = defaultGetParamsKey;
27
- const useAssertValueNotChanged = (name, value) => {
28
- const firstMountRef = (0, react_1.useRef)(false);
29
- (0, react_1.useMemo)(() => {
30
- if (firstMountRef.current) {
31
- throw new Error(`${name} should not be modified`);
32
- }
33
- firstMountRef.current = true;
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [value]);
36
- };
37
- exports.useAssertValueNotChanged = useAssertValueNotChanged;
26
+ exports.defaultGetCacheKey = defaultGetCacheKey;
38
27
  const log = (tag, data) => {
39
28
  console.debug(`@${exports.PACKAGE_SHORT_NAME} [${tag}]`, data);
40
29
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "react-redux-cache",
3
3
  "author": "Alexander Danilov",
4
4
  "license": "MIT",
5
- "version": "0.0.11",
5
+ "version": "0.1.1",
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",
@@ -10,7 +10,7 @@
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
+ "build": "yarn clean && yarn lint && tsc",
14
14
  "test": "node node_modules/jest/bin/jest.js",
15
15
  "prepublishOnly": "yarn build && yarn test"
16
16
  },