react-redux-cache 0.0.4 → 0.0.6

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.
@@ -5,7 +5,7 @@ import { useQuery } from './useQuery';
5
5
  /**
6
6
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
7
7
  */
8
- export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: OptionalPartial<Cache<T, QP, QR, MP, MR>, "options">) => {
8
+ export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: OptionalPartial<Cache<T, QP, QR, MP, MR>, "queries" | "mutations" | "options">) => {
9
9
  cache: Cache<T, QP, QR, MP, MR>;
10
10
  /** Reducer of the cache, should be added to redux store. */
11
11
  reducer: (state: {
@@ -10,15 +10,17 @@ const utilsAndConstants_1 = require("./utilsAndConstants");
10
10
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
11
11
  */
12
12
  const createCache = (cache) => {
13
- var _a, _b, _c, _d;
14
- var _e, _f, _g;
13
+ var _a, _b, _c, _d, _e, _f;
14
+ var _g, _h, _j;
15
15
  // @ts-expect-error hot
16
16
  const hotReloadEnabled = Boolean(module === null || module === void 0 ? void 0 : module.hot);
17
17
  // provide all optional fields
18
18
  (_a = cache.options) !== null && _a !== void 0 ? _a : (cache.options = {});
19
- (_b = (_e = cache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_e.logsEnabled = false);
20
- (_c = (_f = cache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_f.validateFunctionArguments = utilsAndConstants_1.isDev);
21
- (_d = (_g = cache.options).validateHookArguments) !== null && _d !== void 0 ? _d : (_g.validateHookArguments = utilsAndConstants_1.isDev && !hotReloadEnabled);
19
+ (_b = (_g = cache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_g.logsEnabled = false);
20
+ (_c = (_h = cache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_h.validateFunctionArguments = utilsAndConstants_1.isDev);
21
+ (_d = (_j = cache.options).validateHookArguments) !== null && _d !== void 0 ? _d : (_j.validateHookArguments = utilsAndConstants_1.isDev && !hotReloadEnabled);
22
+ (_e = cache.queries) !== null && _e !== void 0 ? _e : (cache.queries = {});
23
+ (_f = cache.mutations) !== null && _f !== void 0 ? _f : (cache.mutations = {});
22
24
  const nonPartialCache = cache;
23
25
  // make selectors
24
26
  const entitiesSelector = (state) => {
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export type { ReduxCacheState } from './reducer';
3
3
  export * from './types';
4
4
  export { defaultMutationCacheOptions } from './useMutation';
5
5
  export { defaultQueryCacheOptions, queryCacheOptionsByPolicy } from './useQuery';
6
- export { defaultGetParamsKey, defaultQueryMutationState, processEntityChanges, } from './utilsAndConstants';
6
+ export { defaultCacheOptions, defaultGetParamsKey, defaultQueryMutationState, processEntityChanges, } from './utilsAndConstants';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ 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.processEntityChanges = exports.defaultQueryMutationState = exports.defaultGetParamsKey = exports.queryCacheOptionsByPolicy = exports.defaultQueryCacheOptions = exports.defaultMutationCacheOptions = exports.createCache = void 0;
17
+ exports.processEntityChanges = exports.defaultQueryMutationState = exports.defaultGetParamsKey = exports.defaultCacheOptions = exports.queryCacheOptionsByPolicy = exports.defaultQueryCacheOptions = exports.defaultMutationCacheOptions = 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);
@@ -24,14 +24,16 @@ var useQuery_1 = require("./useQuery");
24
24
  Object.defineProperty(exports, "defaultQueryCacheOptions", { enumerable: true, get: function () { return useQuery_1.defaultQueryCacheOptions; } });
25
25
  Object.defineProperty(exports, "queryCacheOptionsByPolicy", { enumerable: true, get: function () { return useQuery_1.queryCacheOptionsByPolicy; } });
26
26
  var utilsAndConstants_1 = require("./utilsAndConstants");
27
+ Object.defineProperty(exports, "defaultCacheOptions", { enumerable: true, get: function () { return utilsAndConstants_1.defaultCacheOptions; } });
27
28
  Object.defineProperty(exports, "defaultGetParamsKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetParamsKey; } });
28
29
  Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.defaultQueryMutationState; } });
29
30
  Object.defineProperty(exports, "processEntityChanges", { enumerable: true, get: function () { return utilsAndConstants_1.processEntityChanges; } });
30
31
  // Backlog
31
32
  // ! high
32
- // package.json exports
33
33
  // cover with tests
34
34
  // ! medium
35
+ // type extractors from cache
36
+ // custom useStore
35
37
  // return back deserialize selector?
36
38
  // resultSelector - return also boolean that result is full enough
37
39
  // selector for entities by typename
@@ -51,6 +53,7 @@ Object.defineProperty(exports, "processEntityChanges", { enumerable: true, get:
51
53
  // make error type generic
52
54
  // proper types, remove as, any, todo
53
55
  // ! low
56
+ // remove defaultState and keep values undefined?
54
57
  // add params to the state?
55
58
  // cancellation to queries
56
59
  // if mutation & query alrady loading - make options: last, throttle, debounce, parallel?
package/dist/useQuery.js CHANGED
@@ -24,6 +24,7 @@ exports.queryCacheOptionsByPolicy = {
24
24
  'cache-and-fetch': Object.assign(Object.assign({}, cacheFirstOptions), { policy: 'cache-and-fetch' }),
25
25
  };
26
26
  exports.defaultQueryCacheOptions = cacheFirstOptions;
27
+ const defaultRefState = {};
27
28
  const useQuery = (cache, options) => {
28
29
  var _a, _b, _c, _d;
29
30
  const getParamsKey = (_a = cache.queries[options.query].getParamsKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetParamsKey);
@@ -56,39 +57,43 @@ const useQuery = (cache, options) => {
56
57
  const forceUpdate = (0, utilsAndConstants_1.useForceUpdate)();
57
58
  // Keeps most of local state.
58
59
  // Reference because state is changed not only by changing hook arguments, but also by calling fetch, and it should be done synchronously.
59
- const stateRef = (0, react_1.useRef)({});
60
+ const stateRef = (0, react_1.useRef)(defaultRefState);
60
61
  (0, react_1.useMemo)(() => {
61
- if (skip || stateRef.current.paramsKey === hookParamsKey) {
62
+ if (stateRef.current.paramsKey === hookParamsKey) {
62
63
  return;
63
64
  }
64
- const resultSelectorImpl = cache.queries[queryKey].resultSelector;
65
65
  const state = stateRef.current;
66
+ state.resultSelector = createResultSelector(
67
+ // @ts-expect-error fix later
68
+ cache.queries[queryKey].resultSelector, cache.cacheStateSelector, hookParams);
69
+ if (skip) {
70
+ return;
71
+ }
66
72
  state.params = hookParams;
67
73
  state.paramsKey = hookParamsKey;
68
74
  state.latestHookParamsKey = state.paramsKey;
69
75
  // @ts-expect-error fix later
70
76
  state.cacheKey = getCacheKey(hookParams);
71
- state.resultSelector = createResultSelector(
72
- // @ts-expect-error fix later
73
- resultSelectorImpl, cache.cacheStateSelector, hookParams);
74
77
  // eslint-disable-next-line react-hooks/exhaustive-deps
75
78
  }, [hookParamsKey, skip]);
76
79
  const resultFromSelector =
77
80
  // eslint-disable-next-line react-hooks/rules-of-hooks
78
81
  stateRef.current.resultSelector && (0, react_redux_1.useSelector)(stateRef.current.resultSelector);
79
82
  const hasResultFromSelector = resultFromSelector !== undefined;
80
- const queryStateSelector = (0, react_1.useCallback)((state) => {
83
+ const queryStateSelector = (0, react_1.useCallback)((state, cacheKey = stateRef.current.cacheKey) => {
81
84
  cache.options.logsEnabled &&
82
85
  (0, utilsAndConstants_1.log)('queryStateSelector', {
83
86
  state,
84
87
  queryKey,
85
- cacheKey: stateRef.current.cacheKey,
88
+ cacheKey,
86
89
  cacheState: cache.cacheStateSelector(state),
87
90
  });
88
- const queryState = cache.cacheStateSelector(state).queries[queryKey][stateRef.current.cacheKey];
91
+ const queryState = cache.cacheStateSelector(state).queries[queryKey][cacheKey];
89
92
  return queryState; // TODO proper type
90
- // eslint-disable-next-line react-hooks/exhaustive-deps
91
- }, []);
93
+ },
94
+ // cacheKey needed only to re-evaluate queryStateSelector later
95
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ [stateRef.current.cacheKey]);
92
97
  const queryStateFromSelector = (_d = (0, react_redux_1.useSelector)(queryStateSelector)) !== null && _d !== void 0 ? _d : utilsAndConstants_1.defaultQueryMutationState;
93
98
  const queryState = hasResultFromSelector
94
99
  ? (Object.assign(Object.assign({}, queryStateFromSelector), { result: resultFromSelector }))
@@ -99,11 +104,11 @@ const useQuery = (cache, options) => {
99
104
  if (queryState.loading) {
100
105
  return;
101
106
  }
107
+ const { params, cacheKey } = stateRef.current;
102
108
  cacheOptions.cacheQueryState &&
103
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, stateRef.current.cacheKey, {
109
+ store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
104
110
  loading: true,
105
111
  }));
106
- const { paramsKey, params } = stateRef.current;
107
112
  let response;
108
113
  const fetchFn = cache.queries[queryKey].query;
109
114
  try {
@@ -112,17 +117,14 @@ const useQuery = (cache, options) => {
112
117
  params);
113
118
  }
114
119
  catch (error) {
115
- if (stateRef.current.paramsKey === paramsKey && cacheOptions.cacheQueryState) {
116
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, stateRef.current.cacheKey, {
117
- error: error,
118
- loading: false,
119
- }));
120
- }
120
+ store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
121
+ error: error,
122
+ loading: false,
123
+ }));
121
124
  }
122
- if (response && stateRef.current.paramsKey === paramsKey) {
123
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, stateRef.current.cacheKey, !cacheOptions.cacheQueryState
124
- ? undefined
125
- : {
125
+ if (response) {
126
+ const newState = cacheOptions.cacheQueryState
127
+ ? {
126
128
  error: undefined,
127
129
  loading: false,
128
130
  result: hasResultFromSelector
@@ -130,13 +132,18 @@ const useQuery = (cache, options) => {
130
132
  : mergeResults
131
133
  ? mergeResults(
132
134
  // @ts-expect-error fix later
133
- (_e = queryStateSelector(store.getState())) === null || _e === void 0 ? void 0 : _e.result, response, params)
135
+ (_e = queryStateSelector(store.getState(), cacheKey)) === null || _e === void 0 ? void 0 : _e.result, response, params)
134
136
  : response.result,
135
- }, cacheOptions.cacheEntities ? response : undefined));
137
+ }
138
+ : undefined;
139
+ store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, newState, cacheOptions.cacheEntities ? response : undefined));
136
140
  }
137
141
  // eslint-disable-next-line react-hooks/exhaustive-deps
138
142
  }), [mergeResults, queryState.loading, hasResultFromSelector]);
139
143
  (0, react_1.useEffect)(() => {
144
+ if (skip) {
145
+ return;
146
+ }
140
147
  if (queryState.result != null && cacheOptions.policy === 'cache-first') {
141
148
  return;
142
149
  }
@@ -165,6 +172,13 @@ const useQuery = (cache, options) => {
165
172
  },
166
173
  // eslint-disable-next-line react-hooks/exhaustive-deps
167
174
  [fetchImpl, getCacheKey]);
175
+ cache.options.logsEnabled &&
176
+ console.debug('[useQuery]', {
177
+ state: stateRef.current,
178
+ options,
179
+ resultFromSelector,
180
+ queryState,
181
+ });
168
182
  return [queryState, fetch];
169
183
  };
170
184
  exports.useQuery = useQuery;
@@ -2,8 +2,14 @@
2
2
  import { CacheOptions, EntitiesMap, EntityChanges, Typenames } from './types';
3
3
  export declare const PACKAGE_SHORT_NAME = "RRC";
4
4
  export declare const isDev: boolean;
5
+ export declare const defaultCacheOptions: {
6
+ logsEnabled: boolean;
7
+ validateFunctionArguments: boolean;
8
+ validateHookArguments: boolean;
9
+ };
5
10
  export declare const defaultQueryMutationState: {
6
11
  readonly loading: false;
12
+ readonly error: undefined;
7
13
  };
8
14
  export declare const defaultGetParamsKey: <P = unknown>(params: P) => string;
9
15
  /**
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processEntityChanges = exports.log = exports.useAssertValueNotChanged = exports.useForceUpdate = exports.defaultGetParamsKey = exports.defaultQueryMutationState = exports.isDev = exports.PACKAGE_SHORT_NAME = void 0;
3
+ exports.processEntityChanges = exports.log = exports.useAssertValueNotChanged = exports.useForceUpdate = exports.defaultGetParamsKey = exports.defaultQueryMutationState = exports.defaultCacheOptions = exports.isDev = exports.PACKAGE_SHORT_NAME = void 0;
4
4
  const react_1 = require("react");
5
5
  const react_2 = require("react");
6
6
  exports.PACKAGE_SHORT_NAME = 'RRC';
@@ -13,7 +13,12 @@ exports.isDev = (() => {
13
13
  return process.env.NODE_ENV === 'development';
14
14
  }
15
15
  })();
16
- exports.defaultQueryMutationState = { loading: false };
16
+ exports.defaultCacheOptions = {
17
+ logsEnabled: false,
18
+ validateFunctionArguments: true,
19
+ validateHookArguments: true,
20
+ };
21
+ exports.defaultQueryMutationState = { loading: false, error: undefined };
17
22
  const defaultGetParamsKey = (params) => {
18
23
  switch (typeof params) {
19
24
  case 'string':
@@ -83,13 +88,6 @@ const processEntityChanges = (entities, changes, options) => {
83
88
  if (totalKeysInResponse !== 0 && idsSet.size !== totalKeysInResponse) {
84
89
  throw new Error('Merge, replace and remove changes have intersections for: ' + typename);
85
90
  }
86
- console.log('[VALIDATe]', {
87
- totalKeysInResponse,
88
- idsSet,
89
- mergeIds,
90
- replaceIds,
91
- entitiesToRemove,
92
- });
93
91
  }
94
92
  const newEntities = Object.assign({}, entities[typename]);
95
93
  // remove
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.4",
5
+ "version": "0.0.6",
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,10 +10,11 @@
10
10
  "example": "(cd example && yarn && yarn start)",
11
11
  "clean": "rm -rf dist",
12
12
  "build": "yarn clean && tsc && yarn pack -f package.tgz",
13
- "test": "node node_modules/jest/bin/jest.js",
13
+ "test": "node node_modules/jest/bin/jest.js --env=jsdom",
14
14
  "prepublishOnly": "yarn build && yarn test"
15
15
  },
16
16
  "devDependencies": {
17
+ "@testing-library/jest-dom": "6.1.4",
17
18
  "@testing-library/react": "14.0.0",
18
19
  "@types/jest": "29.5.1",
19
20
  "@types/node": "20.1.2",
@@ -27,12 +28,15 @@
27
28
  "eslint-plugin-react-hooks": "4.6.0",
28
29
  "eslint-plugin-simple-import-sort": "10.0.0",
29
30
  "jest": "29.5.0",
31
+ "jest-environment-jsdom": "29.7.0",
30
32
  "prettier": "2.8.8",
31
33
  "react": "18.2.0",
32
34
  "react-dom": "18.2.0",
33
35
  "react-redux": "8.0.5",
36
+ "react-router-dom": "6.18.0",
34
37
  "redux": "4.2.1",
35
38
  "redux-logger": "3.0.6",
39
+ "redux-persist": "6.0.0",
36
40
  "ts-jest": "29.1.0",
37
41
  "typescript": "5.0.4"
38
42
  },