react-redux-cache 0.18.4 → 0.19.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.
@@ -27,7 +27,7 @@ const withTypenames = () => {
27
27
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
28
28
  var _o, _p, _q, _r, _s, _t;
29
29
  const abortControllers = new WeakMap();
30
- // provide all optional fields
30
+ // Provide all optional fields
31
31
  (_a = partialCache.options) !== null && _a !== void 0 ? _a : (partialCache.options = {});
32
32
  (_b = (_o = partialCache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_o.logsEnabled = false);
33
33
  (_c = (_p = partialCache.options).additionalValidation) !== null && _c !== void 0 ? _c : (_p.additionalValidation = utilsAndConstants_1.IS_DEV);
@@ -37,8 +37,8 @@ const withTypenames = () => {
37
37
  (_g = (_s = partialCache.globals.queries).fetchPolicy) !== null && _g !== void 0 ? _g : (_s.fetchPolicy = utilsAndConstants_1.FetchPolicy.NoCacheOrExpired);
38
38
  (_h = (_t = partialCache.globals.queries).skipFetch) !== null && _h !== void 0 ? _h : (_t.skipFetch = false);
39
39
  (_j = partialCache.storeHooks) !== null && _j !== void 0 ? _j : (partialCache.storeHooks = {
40
- useStore: require.call(undefined, 'react-redux').useStore,
41
- useSelector: require.call(undefined, 'react-redux').useSelector,
40
+ useStore: require('react-redux').useStore,
41
+ useSelector: require('react-redux').useSelector,
42
42
  });
43
43
  (_k = partialCache.cacheStateSelector) !== null && _k !== void 0 ? _k : (partialCache.cacheStateSelector = (state) => state[cache.name]);
44
44
  (_l = partialCache.mutations) !== null && _l !== void 0 ? _l : (partialCache.mutations = {});
@@ -46,19 +46,31 @@ const withTypenames = () => {
46
46
  // @ts-expect-error private field for testing
47
47
  partialCache.abortControllers = abortControllers;
48
48
  const cache = partialCache;
49
- // validate options
49
+ // Validate options
50
50
  if (cache.options.deepComparisonEnabled && !utilsAndConstants_1.optionalUtils.deepEqual) {
51
51
  console.warn('react-redux-cache: optional dependency for fast-deep-equal was not provided, while deepComparisonEnabled option is true');
52
52
  }
53
- // selectors
53
+ // State comparers
54
+ /** Transforms array of keys to comparer function. */
55
+ const setDefaultComparer = (target) => {
56
+ if ((target === null || target === void 0 ? void 0 : target.selectorComparer) != null && typeof target.selectorComparer === 'object') {
57
+ target.selectorComparer = (0, utilsAndConstants_1.createStateComparer)(target.selectorComparer);
58
+ }
59
+ };
60
+ setDefaultComparer(cache.globals.queries);
61
+ for (const queryKey in partialCache.queries) {
62
+ // @ts-expect-error TODO fix types
63
+ setDefaultComparer(partialCache.queries[queryKey]);
64
+ }
65
+ // Selectors
54
66
  const selectors = Object.assign({ selectCacheState: cache.cacheStateSelector }, (0, createSelectors_1.createSelectors)(cache));
55
67
  const { selectCacheState, selectQueryState, selectQueryResult, selectQueryLoading, selectQueryError, selectQueryParams, selectQueryExpiresAt, selectMutationState, selectMutationResult, selectMutationLoading, selectMutationError, selectMutationParams, selectEntityById, selectEntities, selectEntitiesByTypename, } = selectors;
56
- // actions
68
+ // Actions
57
69
  const actions = (0, createActions_1.createActions)(cache.name);
58
70
  const { updateQueryStateAndEntities, updateMutationStateAndEntities, mergeEntityChanges, invalidateQuery, clearQueryState, clearMutationState, clearCache, } = actions;
59
- // reducer
71
+ // Reducer
60
72
  const reducer = (0, createCacheReducer_1.createCacheReducer)(actions, Object.keys(cache.queries), cache.options);
61
- // createClient
73
+ // Client creator
62
74
  const createClient = (store) => {
63
75
  const client = {
64
76
  query: (options) => {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { createCache, withTypenames } from './createCache';
2
2
  export * from './types';
3
- export { useQuerySelectorStateComparer } from './useQuery';
4
- export { defaultGetCacheKey, FetchPolicy, isEmptyObject } from './utilsAndConstants';
3
+ export { createStateComparer, defaultGetCacheKey, FetchPolicy, isEmptyObject } from './utilsAndConstants';
package/dist/index.js CHANGED
@@ -14,14 +14,13 @@ 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.isEmptyObject = exports.FetchPolicy = exports.defaultGetCacheKey = exports.useQuerySelectorStateComparer = exports.withTypenames = exports.createCache = void 0;
17
+ exports.isEmptyObject = exports.FetchPolicy = exports.defaultGetCacheKey = exports.createStateComparer = exports.withTypenames = 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
  Object.defineProperty(exports, "withTypenames", { enumerable: true, get: function () { return createCache_1.withTypenames; } });
21
21
  __exportStar(require("./types"), exports);
22
- var useQuery_1 = require("./useQuery");
23
- Object.defineProperty(exports, "useQuerySelectorStateComparer", { enumerable: true, get: function () { return useQuery_1.useQuerySelectorStateComparer; } });
24
22
  var utilsAndConstants_1 = require("./utilsAndConstants");
23
+ Object.defineProperty(exports, "createStateComparer", { enumerable: true, get: function () { return utilsAndConstants_1.createStateComparer; } });
25
24
  Object.defineProperty(exports, "defaultGetCacheKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetCacheKey; } });
26
25
  Object.defineProperty(exports, "FetchPolicy", { enumerable: true, get: function () { return utilsAndConstants_1.FetchPolicy; } });
27
26
  Object.defineProperty(exports, "isEmptyObject", { enumerable: true, get: function () { return utilsAndConstants_1.isEmptyObject; } });
package/dist/types.d.ts CHANGED
@@ -45,6 +45,7 @@ export type Cache<N extends string, T extends Typenames, QP, QR, MP, MR> = {
45
45
  [MK in keyof (MP & MR)]: MK extends keyof (MP | MR) ? MutationInfo<N, T, MP[MK], MR[MK], QP, QR, MP, MR> : never;
46
46
  };
47
47
  };
48
+ export type QueryStateComparer<T extends Typenames, P, R> = (x: QueryState<T, P, R> | undefined, y: QueryState<T, P, R> | undefined) => boolean;
48
49
  export type Globals<N extends string, T extends Typenames, QP, QR, MP, MR> = {
49
50
  /** Handles errors, not handled by onError from queries and mutations. @Default undefined. */
50
51
  onError?: (error: unknown, key: string, params: unknown, store: Store, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>) => void;
@@ -58,6 +59,8 @@ export type Globals<N extends string, T extends Typenames, QP, QR, MP, MR> = {
58
59
  skipFetch: boolean;
59
60
  /** If set, this value updates expiresAt value of query state when query result is received. @Default undefined */
60
61
  secondsToLive?: number;
62
+ /** Either comparer function, or array of keys to subscribe by useQuery's useSelector. @Default compares result, loading, params, error. */
63
+ selectorComparer?: QueryStateComparer<T, unknown, unknown> | (keyof QueryState<T, unknown, unknown>)[];
61
64
  };
62
65
  };
63
66
  export type CacheOptions = {
@@ -111,6 +114,8 @@ export type QueryInfo<N extends string, T extends Typenames = Typenames, P = unk
111
114
  onSuccess?: (response: NormalizedQueryResponse<T, R>, params: P | undefined, store: Store, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>) => void;
112
115
  /** Called after fetch finished with error. Should return true if error was handled and does not require global onError handling. */
113
116
  onError?: (error: unknown, params: P | undefined, store: Store, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>) => boolean | void | null | undefined;
117
+ /** Either comparer function, or array of keys to subscribe by useQuery's useSelector. Default compares params, result, loading, error. */
118
+ selectorComparer?: QueryStateComparer<T, P, R> | (keyof QueryState<T, P, R>)[];
114
119
  };
115
120
  export type Query<P = unknown, R = unknown> = (
116
121
  /** Query parameters */
@@ -129,7 +134,7 @@ export type QueryState<T extends Typenames, P, R> = MutationState<T, P, R> & {
129
134
  export type UseQueryOptions<N extends string, T extends Typenames, QK extends keyof (QP & QR), QP, QR, MP, MR> = {
130
135
  query: QK;
131
136
  params: QK extends keyof (QP | QR) ? QP[QK] : never;
132
- } & Pick<QueryInfo<N, T, QK extends keyof (QP | QR) ? QP[QK] : never, QK extends keyof (QP | QR) ? QR[QK] : never, QP, QR, MP, MR>, 'fetchPolicy' | 'skipFetch' | 'secondsToLive' | 'mergeResults' | 'onCompleted' | 'onSuccess' | 'onError'>;
137
+ } & Pick<QueryInfo<N, T, QK extends keyof (QP | QR) ? QP[QK] : never, QK extends keyof (QP | QR) ? QR[QK] : never, QP, QR, MP, MR>, 'fetchPolicy' | 'skipFetch' | 'secondsToLive' | 'selectorComparer' | 'mergeResults' | 'onCompleted' | 'onSuccess' | 'onError'>;
133
138
  export type QueryOptions<N extends string, T extends Typenames, QP, QR, QK extends keyof (QP & QR), MP, MR> = Omit<UseQueryOptions<N, T, QK, QP, QR, MP, MR>, 'skipFetch'> & {
134
139
  /** If set to true, query will run only if it is expired or result not yet cached. */
135
140
  onlyIfExpired?: boolean;
@@ -2,5 +2,3 @@ import { Actions } from './createActions';
2
2
  import { Selectors } from './createSelectors';
3
3
  import { Cache, QueryOptions, QueryState, Typenames, UseQueryOptions } from './types';
4
4
  export declare const useQuery: <N extends string, T extends Typenames, QP, QR, MP, MR, QK extends keyof (QP & QR)>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Actions<N, T, QP, QR, MP, MR>, selectors: Selectors<N, T, QP, QR, MP, MR>, options: UseQueryOptions<N, T, QK, QP, QR, MP, MR>) => readonly [Omit<QueryState<T, QK extends keyof QP & keyof QR ? QP[QK] : never, QK extends keyof QP & keyof QR ? QR[QK] : never>, "expiresAt">, (options?: Partial<Pick<QueryOptions<N, T, QP, QR, QK, MP, MR>, "params" | "onlyIfExpired">>) => Promise<import("./types").QueryResult<QK extends infer T_1 ? T_1 extends QK ? T_1 extends keyof QP & keyof QR ? QR[T_1] : never : never : never>>];
5
- /** Omit `expiresAt` from comparison */
6
- export declare const useQuerySelectorStateComparer: <T extends Typenames, P, R>(state1: QueryState<T, P, R> | undefined, state2: QueryState<T, P, R> | undefined) => boolean;
package/dist/useQuery.js CHANGED
@@ -9,16 +9,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.useQuerySelectorStateComparer = exports.useQuery = void 0;
12
+ exports.useQuery = void 0;
13
13
  const react_1 = require("react");
14
14
  const query_1 = require("./query");
15
15
  const utilsAndConstants_1 = require("./utilsAndConstants");
16
16
  const useQuery = (cache, actions, selectors, options) => {
17
- var _a, _b, _c;
18
- const { query: queryKey, skipFetch = false, params, secondsToLive, fetchPolicy = (_a = cache.queries[queryKey].fetchPolicy) !== null && _a !== void 0 ? _a : cache.globals.queries.fetchPolicy, mergeResults, onCompleted, onSuccess, onError, } = options;
17
+ var _a, _b, _c, _d, _e;
18
+ const { query: queryKey, skipFetch = false, params, secondsToLive, selectorComparer, fetchPolicy = (_a = cache.queries[queryKey].fetchPolicy) !== null && _a !== void 0 ? _a : cache.globals.queries.fetchPolicy, mergeResults, onCompleted, onSuccess, onError, } = options;
19
19
  const { selectQueryState } = selectors;
20
+ const queryInfo = cache.queries[queryKey];
20
21
  const logsEnabled = cache.options.logsEnabled;
21
- const getCacheKey = (_b = cache.queries[queryKey].getCacheKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetCacheKey);
22
+ const getCacheKey = (_b = queryInfo.getCacheKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetCacheKey);
23
+ const comparer = selectorComparer === undefined
24
+ ? (_d = (_c = queryInfo.selectorComparer) !== null && _c !== void 0 ? _c : cache.globals.queries.selectorComparer) !== null && _d !== void 0 ? _d : defaultStateComparer
25
+ : typeof selectorComparer === 'function'
26
+ ? selectorComparer
27
+ : (0, utilsAndConstants_1.createStateComparer)(selectorComparer);
22
28
  const store = cache.storeHooks.useStore();
23
29
  // @ts-expect-error fix types later
24
30
  const cacheKey = getCacheKey(params);
@@ -35,9 +41,9 @@ const useQuery = (cache, actions, selectors, options) => {
35
41
  // eslint-disable-next-line react-hooks/exhaustive-deps
36
42
  [store, queryKey, cacheKey]);
37
43
  /** Query state */
38
- const queryState = (_c = cache.storeHooks.useSelector((state) => {
44
+ const queryState = (_e = cache.storeHooks.useSelector((state) => {
39
45
  return selectQueryState(state, queryKey, cacheKey); // TODO proper type
40
- }, (exports.useQuerySelectorStateComparer))) !== null && _c !== void 0 ? _c : utilsAndConstants_1.EMPTY_OBJECT;
46
+ }, comparer)) !== null && _e !== void 0 ? _e : utilsAndConstants_1.EMPTY_OBJECT;
41
47
  (0, react_1.useEffect)(() => {
42
48
  if (skipFetch) {
43
49
  logsEnabled && (0, utilsAndConstants_1.log)('useQuery.useEffect skip fetch', { skipFetch, queryKey, cacheKey });
@@ -68,17 +74,4 @@ const useQuery = (cache, actions, selectors, options) => {
68
74
  return [queryState, performFetch];
69
75
  };
70
76
  exports.useQuery = useQuery;
71
- /** Omit `expiresAt` from comparison */
72
- const useQuerySelectorStateComparer = (state1, state2) => {
73
- if (state1 === state2) {
74
- return true;
75
- }
76
- if (state1 === undefined || state2 === undefined) {
77
- return false;
78
- }
79
- return (state1.params === state2.params &&
80
- state1.loading === state2.loading &&
81
- state1.result === state2.result &&
82
- state1.error === state2.error);
83
- };
84
- exports.useQuerySelectorStateComparer = useQuerySelectorStateComparer;
77
+ const defaultStateComparer = (0, utilsAndConstants_1.createStateComparer)(['result', 'loading', 'params', 'error']);
@@ -1,4 +1,4 @@
1
- import type { CacheOptions, EntitiesMap, EntityChanges, Key, QueryState, Typenames } from './types';
1
+ import type { CacheOptions, EntitiesMap, EntityChanges, Key, QueryState, QueryStateComparer, Typenames } from './types';
2
2
  export declare const PACKAGE_SHORT_NAME = "rrc";
3
3
  export declare const optionalUtils: {
4
4
  deepEqual?: (a: any, b: any) => boolean;
@@ -17,3 +17,4 @@ export declare const FetchPolicy: {
17
17
  };
18
18
  export declare const applyEntityChanges: <T extends Typenames>(entities: EntitiesMap<T>, changes: EntityChanges<T>, options: CacheOptions) => EntitiesMap<T> | undefined;
19
19
  export declare const isEmptyObject: (o: object) => boolean;
20
+ export declare const createStateComparer: <T extends Typenames = Typenames, Q = unknown, P = unknown>(fields: (keyof QueryState<T, Q, P>)[]) => QueryStateComparer<T, Q, P>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isEmptyObject = exports.applyEntityChanges = exports.FetchPolicy = exports.log = exports.defaultGetCacheKey = exports.NOOP = exports.EMPTY_ARRAY = exports.EMPTY_OBJECT = exports.IS_DEV = exports.optionalUtils = exports.PACKAGE_SHORT_NAME = void 0;
3
+ exports.createStateComparer = exports.isEmptyObject = exports.applyEntityChanges = exports.FetchPolicy = exports.log = exports.defaultGetCacheKey = exports.NOOP = exports.EMPTY_ARRAY = exports.EMPTY_OBJECT = exports.IS_DEV = exports.optionalUtils = exports.PACKAGE_SHORT_NAME = void 0;
4
4
  exports.PACKAGE_SHORT_NAME = 'rrc';
5
5
  exports.optionalUtils = {
6
6
  deepEqual: undefined,
@@ -141,3 +141,21 @@ const isEmptyObject = (o) => {
141
141
  return true;
142
142
  };
143
143
  exports.isEmptyObject = isEmptyObject;
144
+ const createStateComparer = (fields) => {
145
+ return (x, y) => {
146
+ if (x === y) {
147
+ return true;
148
+ }
149
+ if (x === undefined || y === undefined) {
150
+ return false;
151
+ }
152
+ for (let i = 0; i < fields.length; i += 1) {
153
+ const key = fields[i];
154
+ if (x[key] !== y[key]) {
155
+ return false;
156
+ }
157
+ }
158
+ return true;
159
+ };
160
+ };
161
+ exports.createStateComparer = createStateComparer;
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.18.4",
5
+ "version": "0.19.1",
6
6
  "description": "Powerful data fetching and caching library for Redux and Zustand that supports normalization.",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",