react-redux-cache 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -2
- package/dist/cjs/createCache.js +34 -20
- package/dist/cjs/createReducer.js +183 -110
- package/dist/cjs/createSelectors.js +1 -1
- package/dist/cjs/utilsAndConstants.js +41 -12
- package/dist/esm/createCache.js +34 -20
- package/dist/esm/createReducer.js +194 -114
- package/dist/esm/createSelectors.js +1 -1
- package/dist/esm/utilsAndConstants.js +39 -11
- package/dist/types/createCache.d.ts +27 -8
- package/dist/types/createSelectors.d.ts +7 -7
- package/dist/types/types.d.ts +19 -4
- package/dist/types/utilsAndConstants.d.ts +5 -2
- package/package.json +6 -4
|
@@ -45,7 +45,7 @@ export const defaultGetCacheKey = (params) => {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export const applyEntityChanges = (entities, changes, options) => {
|
|
48
|
-
var _a, _b, _c
|
|
48
|
+
var _a, _b, _c
|
|
49
49
|
if (changes.merge && changes.entities) {
|
|
50
50
|
logWarn('applyEntityChanges', 'merge and entities should not be both set')
|
|
51
51
|
}
|
|
@@ -53,6 +53,7 @@ export const applyEntityChanges = (entities, changes, options) => {
|
|
|
53
53
|
if (!merge && !replace && !remove) {
|
|
54
54
|
return undefined
|
|
55
55
|
}
|
|
56
|
+
const mutable = options.mutableCollections
|
|
56
57
|
const deepEqual = options.deepComparisonEnabled ? optionalUtils.deepEqual : undefined
|
|
57
58
|
let result
|
|
58
59
|
const objectWithAllTypenames = Object.assign(
|
|
@@ -95,37 +96,48 @@ export const applyEntityChanges = (entities, changes, options) => {
|
|
|
95
96
|
logWarn('applyEntityChanges', 'merge, replace and remove changes have intersections for: ' + typename)
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
const oldEntities =
|
|
99
|
+
const oldEntities = entities[typename]
|
|
99
100
|
let newEntities
|
|
100
101
|
entitiesToRemove === null || entitiesToRemove === void 0
|
|
101
102
|
? void 0
|
|
102
103
|
: entitiesToRemove.forEach((id) => {
|
|
103
|
-
if (oldEntities[id]) {
|
|
104
|
+
if (oldEntities === null || oldEntities === void 0 ? void 0 : oldEntities[id]) {
|
|
104
105
|
newEntities !== null && newEntities !== void 0
|
|
105
106
|
? newEntities
|
|
106
|
-
: (newEntities = Object.assign({}, oldEntities))
|
|
107
|
+
: (newEntities = mutable ? oldEntities : Object.assign({}, oldEntities))
|
|
107
108
|
delete newEntities[id]
|
|
108
109
|
}
|
|
109
110
|
})
|
|
110
111
|
if (entitiesToReplace) {
|
|
111
112
|
for (const id in entitiesToReplace) {
|
|
112
113
|
const newEntity = entitiesToReplace[id]
|
|
113
|
-
if (
|
|
114
|
+
if (
|
|
115
|
+
oldEntities === undefined ||
|
|
116
|
+
!(deepEqual === null || deepEqual === void 0 ? void 0 : deepEqual(oldEntities[id], newEntity))
|
|
117
|
+
) {
|
|
114
118
|
newEntities !== null && newEntities !== void 0
|
|
115
119
|
? newEntities
|
|
116
|
-
: (newEntities =
|
|
120
|
+
: (newEntities = mutable
|
|
121
|
+
? oldEntities !== null && oldEntities !== void 0
|
|
122
|
+
? oldEntities
|
|
123
|
+
: {}
|
|
124
|
+
: Object.assign({}, oldEntities))
|
|
117
125
|
newEntities[id] = newEntity
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
}
|
|
121
129
|
if (entitiesToMerge) {
|
|
122
130
|
for (const id in entitiesToMerge) {
|
|
123
|
-
const oldEntity = oldEntities[id]
|
|
131
|
+
const oldEntity = oldEntities === null || oldEntities === void 0 ? void 0 : oldEntities[id]
|
|
124
132
|
const newEntity = Object.assign(Object.assign({}, oldEntity), entitiesToMerge[id])
|
|
125
133
|
if (!(deepEqual === null || deepEqual === void 0 ? void 0 : deepEqual(oldEntity, newEntity))) {
|
|
126
134
|
newEntities !== null && newEntities !== void 0
|
|
127
135
|
? newEntities
|
|
128
|
-
: (newEntities =
|
|
136
|
+
: (newEntities = mutable
|
|
137
|
+
? oldEntities !== null && oldEntities !== void 0
|
|
138
|
+
? oldEntities
|
|
139
|
+
: {}
|
|
140
|
+
: Object.assign({}, oldEntities))
|
|
129
141
|
newEntities[id] = newEntity
|
|
130
142
|
}
|
|
131
143
|
}
|
|
@@ -133,7 +145,15 @@ export const applyEntityChanges = (entities, changes, options) => {
|
|
|
133
145
|
if (!newEntities) {
|
|
134
146
|
continue
|
|
135
147
|
}
|
|
136
|
-
|
|
148
|
+
if (mutable) {
|
|
149
|
+
incrementChangeKey(newEntities)
|
|
150
|
+
if (result === undefined) {
|
|
151
|
+
incrementChangeKey(entities)
|
|
152
|
+
result = entities
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
result !== null && result !== void 0 ? result : (result = Object.assign({}, entities))
|
|
156
|
+
}
|
|
137
157
|
result[typename] = newEntities
|
|
138
158
|
}
|
|
139
159
|
options.logsEnabled &&
|
|
@@ -146,8 +166,8 @@ export const applyEntityChanges = (entities, changes, options) => {
|
|
|
146
166
|
return result
|
|
147
167
|
}
|
|
148
168
|
|
|
149
|
-
export const isEmptyObject = (
|
|
150
|
-
for (const _ in
|
|
169
|
+
export const isEmptyObject = (obj) => {
|
|
170
|
+
for (const _ in obj) {
|
|
151
171
|
return false
|
|
152
172
|
}
|
|
153
173
|
return true
|
|
@@ -177,3 +197,11 @@ export const FetchPolicy = {
|
|
|
177
197
|
},
|
|
178
198
|
Always: () => true,
|
|
179
199
|
}
|
|
200
|
+
|
|
201
|
+
export const incrementChangeKey = (mutable) => {
|
|
202
|
+
if (mutable._changeKey === undefined) {
|
|
203
|
+
mutable._changeKey = 0
|
|
204
|
+
} else {
|
|
205
|
+
mutable._changeKey += 1
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -2,7 +2,6 @@ import type {
|
|
|
2
2
|
Cache,
|
|
3
3
|
CacheOptions,
|
|
4
4
|
CacheState,
|
|
5
|
-
Dict,
|
|
6
5
|
EntitiesMap,
|
|
7
6
|
EntityChanges,
|
|
8
7
|
Globals,
|
|
@@ -127,7 +126,7 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
127
126
|
}
|
|
128
127
|
type: `@rrc/${N}/mergeEntityChanges`
|
|
129
128
|
}
|
|
130
|
-
/**
|
|
129
|
+
/** Sets expiresAt to Date.now(). */
|
|
131
130
|
invalidateQuery: {
|
|
132
131
|
<K extends keyof QP & keyof QR>(
|
|
133
132
|
queries: {
|
|
@@ -255,9 +254,12 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
255
254
|
typename: TN
|
|
256
255
|
) => T[TN] | undefined
|
|
257
256
|
/** Selects all entities. */
|
|
258
|
-
selectEntities: (state: unknown) => EntitiesMap<T>
|
|
257
|
+
selectEntities: (state: unknown) => EntitiesMap<T> & import('./types').Mutable
|
|
259
258
|
/** Selects all entities of provided typename. */
|
|
260
|
-
selectEntitiesByTypename: <TN extends keyof T>(
|
|
259
|
+
selectEntitiesByTypename: <TN extends keyof T>(
|
|
260
|
+
state: unknown,
|
|
261
|
+
typename: TN
|
|
262
|
+
) => (EntitiesMap<T> & import('./types').Mutable)[TN]
|
|
261
263
|
}
|
|
262
264
|
hooks: {
|
|
263
265
|
/** Returns memoized object with query and mutate functions. Memoization dependency is the store. */
|
|
@@ -331,6 +333,13 @@ export declare const withTypenames: <T extends Typenames = Typenames>() => {
|
|
|
331
333
|
]
|
|
332
334
|
/** useSelector + selectEntityById. */
|
|
333
335
|
useSelectEntityById: <TN extends keyof T>(id: Key | null | undefined, typename: TN) => T[TN] | undefined
|
|
336
|
+
/**
|
|
337
|
+
* useSelector + selectEntitiesByTypename. Also subscribes to collection's change key if `mutableCollections` enabled.
|
|
338
|
+
* @warning Subscribing to collections should be avoided.
|
|
339
|
+
* */
|
|
340
|
+
useEntitiesByTypename: <TN extends keyof T>(
|
|
341
|
+
typename: TN
|
|
342
|
+
) => (EntitiesMap<T> & import('./types').Mutable)[TN]
|
|
334
343
|
}
|
|
335
344
|
utils: {
|
|
336
345
|
/** Creates client by providing the store. Can be used when the store is a singleton - to not use a useClient hook for getting the client, but import it directly. */
|
|
@@ -481,7 +490,7 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(
|
|
|
481
490
|
}
|
|
482
491
|
type: `@rrc/${N}/mergeEntityChanges`
|
|
483
492
|
}
|
|
484
|
-
/**
|
|
493
|
+
/** Sets expiresAt to Date.now(). */
|
|
485
494
|
invalidateQuery: {
|
|
486
495
|
<K extends keyof QP & keyof QR>(
|
|
487
496
|
queries: {
|
|
@@ -616,9 +625,12 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(
|
|
|
616
625
|
typename: TN
|
|
617
626
|
) => object | undefined
|
|
618
627
|
/** Selects all entities. */
|
|
619
|
-
selectEntities: (state: unknown) => EntitiesMap<Typenames>
|
|
628
|
+
selectEntities: (state: unknown) => EntitiesMap<Typenames> & import('./types').Mutable
|
|
620
629
|
/** Selects all entities of provided typename. */
|
|
621
|
-
selectEntitiesByTypename: <TN extends string>(
|
|
630
|
+
selectEntitiesByTypename: <TN extends string>(
|
|
631
|
+
state: unknown,
|
|
632
|
+
typename: TN
|
|
633
|
+
) => (EntitiesMap<Typenames> & import('./types').Mutable)[TN]
|
|
622
634
|
}
|
|
623
635
|
hooks: {
|
|
624
636
|
/** Returns memoized object with query and mutate functions. Memoization dependency is the store. */
|
|
@@ -692,6 +704,13 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(
|
|
|
692
704
|
]
|
|
693
705
|
/** useSelector + selectEntityById. */
|
|
694
706
|
useSelectEntityById: <TN extends string>(id: Key | null | undefined, typename: TN) => object | undefined
|
|
707
|
+
/**
|
|
708
|
+
* useSelector + selectEntitiesByTypename. Also subscribes to collection's change key if `mutableCollections` enabled.
|
|
709
|
+
* @warning Subscribing to collections should be avoided.
|
|
710
|
+
* */
|
|
711
|
+
useEntitiesByTypename: <TN extends string>(
|
|
712
|
+
typename: TN
|
|
713
|
+
) => (EntitiesMap<Typenames> & import('./types').Mutable)[TN]
|
|
695
714
|
}
|
|
696
715
|
utils: {
|
|
697
716
|
/** Creates client by providing the store. Can be used when the store is a singleton - to not use a useClient hook for getting the client, but import it directly. */
|
|
@@ -720,7 +739,7 @@ export declare const createCache: <N extends string, QP, QR, MP, MR>(
|
|
|
720
739
|
* Performs additional checks for intersections if `additionalValidation` option is `true`, and prints warnings if finds any issues.
|
|
721
740
|
*/
|
|
722
741
|
applyEntityChanges: (
|
|
723
|
-
entities: EntitiesMap<Typenames
|
|
742
|
+
entities: EntitiesMap<Typenames> & import('./types').Mutable,
|
|
724
743
|
changes: EntityChanges<Typenames>
|
|
725
744
|
) => EntitiesMap<Typenames> | undefined
|
|
726
745
|
}
|
|
@@ -12,6 +12,11 @@ export type Selectors<
|
|
|
12
12
|
export declare const createSelectors: <N extends string, T extends Typenames, QP, QR, MP, MR>(
|
|
13
13
|
cache: Cache<N, T, QP, QR, MP, MR>
|
|
14
14
|
) => {
|
|
15
|
+
selectEntityById: <TN extends keyof T>(
|
|
16
|
+
state: unknown,
|
|
17
|
+
id: Key | null | undefined,
|
|
18
|
+
typename: TN
|
|
19
|
+
) => T[TN] | undefined
|
|
15
20
|
selectQueryState: <QK extends keyof (QP & QR)>(
|
|
16
21
|
state: unknown,
|
|
17
22
|
query: QK,
|
|
@@ -67,14 +72,9 @@ export declare const createSelectors: <N extends string, T extends Typenames, QP
|
|
|
67
72
|
state: unknown,
|
|
68
73
|
mutation: MK
|
|
69
74
|
) => (MK extends keyof MP & keyof MR ? MP[MK] : never) | undefined
|
|
70
|
-
|
|
71
|
-
state: unknown,
|
|
72
|
-
id: Key | null | undefined,
|
|
73
|
-
typename: TN
|
|
74
|
-
) => T[TN] | undefined
|
|
75
|
-
selectEntities: (state: unknown) => import('./types').EntitiesMap<T>
|
|
75
|
+
selectEntities: (state: unknown) => import('./types').EntitiesMap<T> & import('./types').Mutable
|
|
76
76
|
selectEntitiesByTypename: <TN extends keyof T>(
|
|
77
77
|
state: unknown,
|
|
78
78
|
typename: TN
|
|
79
|
-
) => import('./types').EntitiesMap<T>[TN]
|
|
79
|
+
) => (import('./types').EntitiesMap<T> & import('./types').Mutable)[TN]
|
|
80
80
|
}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -3,7 +3,15 @@ import type {Selectors} from './createSelectors'
|
|
|
3
3
|
|
|
4
4
|
export type Key = string | number | symbol
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type Mutable = {
|
|
7
|
+
/**
|
|
8
|
+
* Used only when mutable cache enabled. Always incremented when collection changed by reducer to allow subscribe on changes.
|
|
9
|
+
* Should not be used for comparing different collections as supposed to be compared only with previously saved changeKey of the same collection.
|
|
10
|
+
*/
|
|
11
|
+
_changeKey?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Dict<T> = Record<Key, T> & Mutable
|
|
7
15
|
|
|
8
16
|
export type OptionalPartial<T, K extends keyof T> = Partial<{
|
|
9
17
|
[A in K]: Partial<T[A]>
|
|
@@ -95,6 +103,13 @@ export type Globals<N extends string, T extends Typenames, QP, QR, MP, MR> = {
|
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
export type CacheOptions = {
|
|
106
|
+
/**
|
|
107
|
+
* BETA: Optimization that makes state collections mutable.
|
|
108
|
+
* Subscription to mutable collecitons will work only when subscribed to both collection and its change key - collections
|
|
109
|
+
* still can be replaced with the new ones instead of mutating e.g. when clearing state.
|
|
110
|
+
* @Default false
|
|
111
|
+
* */
|
|
112
|
+
mutableCollections: boolean
|
|
98
113
|
/** Enables additional validation with logging to console.warn. Recommended to enable in dev/testing mode. @Default true in dev mode. */
|
|
99
114
|
additionalValidation: boolean
|
|
100
115
|
/** Enables debug logs. @Default false */
|
|
@@ -121,13 +136,13 @@ export type EntityIds<T extends Typenames> = {
|
|
|
121
136
|
}
|
|
122
137
|
|
|
123
138
|
export type CacheState<T extends Typenames, QP, QR, MP, MR> = {
|
|
124
|
-
entities: EntitiesMap<T>
|
|
139
|
+
entities: EntitiesMap<T> & Mutable
|
|
125
140
|
queries: {
|
|
126
141
|
[QK in keyof (QP | QR)]: Dict<QueryState<T, QP[QK], QR[QK]> | undefined>
|
|
127
|
-
}
|
|
142
|
+
} & Mutable
|
|
128
143
|
mutations: {
|
|
129
144
|
[MK in keyof (MP | MR)]: MutationState<T, MP[MK], MR[MK]>
|
|
130
|
-
}
|
|
145
|
+
} & Mutable
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
export type QueryInfo<
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
EntitiesMap,
|
|
4
4
|
EntityChanges,
|
|
5
5
|
Key,
|
|
6
|
+
Mutable,
|
|
6
7
|
QueryState,
|
|
7
8
|
QueryStateComparer,
|
|
8
9
|
Typenames,
|
|
@@ -31,13 +32,13 @@ export declare const noop: () => void
|
|
|
31
32
|
export declare const defaultGetCacheKey: <P = unknown>(params: P) => Key
|
|
32
33
|
|
|
33
34
|
export declare const applyEntityChanges: <T extends Typenames>(
|
|
34
|
-
entities: EntitiesMap<T
|
|
35
|
+
entities: EntitiesMap<T> & Mutable,
|
|
35
36
|
changes: EntityChanges<T>,
|
|
36
37
|
options: CacheOptions
|
|
37
38
|
) => EntitiesMap<T> | undefined
|
|
38
39
|
|
|
39
40
|
/** Returns true if object has no keys. */
|
|
40
|
-
export declare const isEmptyObject: (
|
|
41
|
+
export declare const isEmptyObject: (obj: object) => boolean
|
|
41
42
|
|
|
42
43
|
/** Returns query state comparer that compares only provided fields. Used in implementation of `selectorComparer` option. */
|
|
43
44
|
export declare const createStateComparer: <T extends Typenames = Typenames, Q = unknown, P = unknown>(
|
|
@@ -57,3 +58,5 @@ export declare const FetchPolicy: {
|
|
|
57
58
|
/** Every fetch trigger. */
|
|
58
59
|
Always: () => boolean
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
export declare const incrementChangeKey: (mutable: Mutable) => void
|
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.
|
|
5
|
+
"version": "0.22.0",
|
|
6
6
|
"description": "Powerful data fetching and caching library for Redux and Zustand that supports normalization.",
|
|
7
7
|
"main": "./dist/cjs/index.js",
|
|
8
8
|
"module": "./dist/esm/index.js",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"example": "(cd example && yarn --production && yarn dev)",
|
|
19
19
|
"clean": "rm -rf dist",
|
|
20
|
-
"lint": "yarn eslint",
|
|
21
|
-
"lint-fix": "yarn eslint --fix",
|
|
20
|
+
"lint": "yarn eslint ./src",
|
|
21
|
+
"lint-fix": "yarn eslint --fix ./src",
|
|
22
22
|
"lint-fix-dist": "yarn eslint --quiet --fix dist/ > /dev/null 2>&1 || true",
|
|
23
23
|
"build-cjs": "tsc -p tsconfig.cjs.json && rm -rf dist/cjs/testing && rm -rf dist/cjs/__tests__",
|
|
24
24
|
"build-esm": "tsc -p tsconfig.esm.json > /dev/null ; rm -rf dist/esm/testing && rm -rf dist/esm/__tests__",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"publish-rc": "npm publish --tag rc",
|
|
32
32
|
"remove-rc": "npm version <same-version-without-rc>",
|
|
33
33
|
"prepublishOnly": "yarn build && yarn test",
|
|
34
|
-
"generate-docs": "node --experimental-strip-types scripts/generate-docs.ts"
|
|
34
|
+
"generate-docs": "node --experimental-strip-types scripts/generate-docs.ts",
|
|
35
|
+
"benchmark": "NODE_ENV=production node -r ts-node/register --expose-gc benchmark.ts"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"fast-deep-equal": "*",
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"redux": "4.2.1",
|
|
73
74
|
"redux-logger": "3.0.6",
|
|
74
75
|
"ts-jest": "29.1.0",
|
|
76
|
+
"ts-node": "10.9.2",
|
|
75
77
|
"typescript": "5.6.3"
|
|
76
78
|
},
|
|
77
79
|
"files": [
|