react-native-onyx 3.0.116 → 3.0.118
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/API.md +15 -5
- package/README.md +8 -8
- package/dist/Onyx.d.ts +17 -14
- package/dist/Onyx.js +125 -38
- package/dist/OnyxCache.d.ts +2 -2
- package/dist/OnyxCache.js +4 -9
- package/dist/OnyxUtils.d.ts +17 -55
- package/dist/OnyxUtils.js +63 -352
- package/dist/PendingWrites.d.ts +35 -0
- package/dist/PendingWrites.js +103 -0
- package/dist/index.d.ts +1 -2
- package/dist/storage/providers/IDBKeyValProvider/classifyError.js +4 -0
- package/dist/storage/providers/IDBKeyValProvider/createStore.js +1 -0
- package/dist/types.d.ts +10 -13
- package/dist/useOnyx.d.ts +11 -10
- package/dist/useOnyx.js +68 -193
- package/package.json +4 -2
- package/dist/OnyxConnectionManager.d.ts +0 -78
- package/dist/OnyxConnectionManager.js +0 -189
- package/dist/OnyxSnapshotCache.d.ts +0 -75
- package/dist/OnyxSnapshotCache.js +0 -125
- package/dist/createMemoizedSelector.d.ts +0 -18
- package/dist/createMemoizedSelector.js +0 -37
- package/dist/memoizedShallowEqual.d.ts +0 -5
- package/dist/memoizedShallowEqual.js +0 -34
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
const lodash_bindall_1 = __importDefault(require("lodash.bindall"));
|
|
40
|
-
const Logger = __importStar(require("./Logger"));
|
|
41
|
-
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
42
|
-
const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
|
|
43
|
-
const Str = __importStar(require("./Str"));
|
|
44
|
-
const OnyxSnapshotCache_1 = __importDefault(require("./OnyxSnapshotCache"));
|
|
45
|
-
/**
|
|
46
|
-
* Manages Onyx connections of `Onyx.connect()` and `useOnyx()` subscribers.
|
|
47
|
-
*/
|
|
48
|
-
class OnyxConnectionManager {
|
|
49
|
-
constructor() {
|
|
50
|
-
this.connectionsMap = new Map();
|
|
51
|
-
this.lastCallbackID = 0;
|
|
52
|
-
this.sessionID = Str.guid();
|
|
53
|
-
// Binds all public methods to prevent problems with `this`.
|
|
54
|
-
(0, lodash_bindall_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID');
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Generates a connection ID based on the `connectOptions` object passed to the function.
|
|
58
|
-
*
|
|
59
|
-
* The properties used to generate the ID are handpicked for performance reasons and
|
|
60
|
-
* according to their purpose and effect they produce in the Onyx connection.
|
|
61
|
-
*/
|
|
62
|
-
generateConnectionID(connectOptions) {
|
|
63
|
-
const { key, reuseConnection } = connectOptions;
|
|
64
|
-
// The current session ID is appended to the connection ID so we can have different connections
|
|
65
|
-
// after an `Onyx.clear()` operation.
|
|
66
|
-
let suffix = `,sessionID=${this.sessionID}`;
|
|
67
|
-
// We will generate a unique ID when `reuseConnection` is `false`, which means the subscriber
|
|
68
|
-
// explicitly wants the connection to not be reused. Collection-root subscriptions are now always
|
|
69
|
-
// snapshot mode, so they can be reused like any other connection.
|
|
70
|
-
if (reuseConnection === false) {
|
|
71
|
-
suffix += `,uniqueID=${Str.guid()}`;
|
|
72
|
-
}
|
|
73
|
-
return `onyxKey=${key}${suffix}`;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Fires all the subscribers callbacks associated with that connection ID.
|
|
77
|
-
*/
|
|
78
|
-
fireCallbacks(connectionID) {
|
|
79
|
-
const connection = this.connectionsMap.get(connectionID);
|
|
80
|
-
if (!connection) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
for (const callback of connection.callbacks.values()) {
|
|
84
|
-
try {
|
|
85
|
-
if (OnyxKeys_1.default.isCollectionKey(connection.onyxKey)) {
|
|
86
|
-
callback(connection.cachedCallbackValue, connection.cachedCallbackKey);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
callback(connection.cachedCallbackValue, connection.cachedCallbackKey);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
Logger.logAlert(`[ConnectionManager] Subscriber callback threw an error for key '${connection.onyxKey}': ${String(error)}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
99
|
-
*
|
|
100
|
-
* @param connectOptions The options object that will define the behavior of the connection.
|
|
101
|
-
* @returns The connection object to use when calling `disconnect()`.
|
|
102
|
-
*/
|
|
103
|
-
connect(connectOptions) {
|
|
104
|
-
const connectionID = this.generateConnectionID(connectOptions);
|
|
105
|
-
let connectionMetadata = this.connectionsMap.get(connectionID);
|
|
106
|
-
let subscriptionID;
|
|
107
|
-
const callbackID = String(this.lastCallbackID++);
|
|
108
|
-
// If there is no connection yet for that connection ID, we create a new one.
|
|
109
|
-
if (!connectionMetadata) {
|
|
110
|
-
const callback = (value, key) => {
|
|
111
|
-
const createdConnection = this.connectionsMap.get(connectionID);
|
|
112
|
-
if (createdConnection) {
|
|
113
|
-
// We signal that the first connection was made and now any new subscribers
|
|
114
|
-
// can fire their callbacks immediately with the cached value when connecting.
|
|
115
|
-
createdConnection.isConnectionMade = true;
|
|
116
|
-
createdConnection.cachedCallbackValue = value;
|
|
117
|
-
createdConnection.cachedCallbackKey = key;
|
|
118
|
-
this.fireCallbacks(connectionID);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
subscriptionID = OnyxUtils_1.default.subscribeToKey(Object.assign(Object.assign({}, connectOptions), { callback }));
|
|
122
|
-
connectionMetadata = {
|
|
123
|
-
subscriptionID,
|
|
124
|
-
onyxKey: connectOptions.key,
|
|
125
|
-
isConnectionMade: false,
|
|
126
|
-
callbacks: new Map(),
|
|
127
|
-
};
|
|
128
|
-
this.connectionsMap.set(connectionID, connectionMetadata);
|
|
129
|
-
}
|
|
130
|
-
// We add the subscriber's callback to the list of callbacks associated with this connection.
|
|
131
|
-
if (connectOptions.callback) {
|
|
132
|
-
connectionMetadata.callbacks.set(callbackID, connectOptions.callback);
|
|
133
|
-
}
|
|
134
|
-
// If the first connection is already made we want any new subscribers to receive the cached callback value immediately.
|
|
135
|
-
if (connectionMetadata.isConnectionMade) {
|
|
136
|
-
// Defer the callback execution to the next tick of the event loop.
|
|
137
|
-
// This ensures that the current execution flow completes and the result connection object is available when the callback fires.
|
|
138
|
-
Promise.resolve().then(() => {
|
|
139
|
-
var _a;
|
|
140
|
-
(_a = connectOptions.callback) === null || _a === void 0 ? void 0 : _a.call(connectOptions, connectionMetadata.cachedCallbackValue, connectionMetadata.cachedCallbackKey);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return { id: connectionID, callbackID };
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Disconnects and removes the listener from the Onyx key.
|
|
147
|
-
*
|
|
148
|
-
* @param connection Connection object returned by calling `connect()`.
|
|
149
|
-
*/
|
|
150
|
-
disconnect(connection) {
|
|
151
|
-
if (!connection) {
|
|
152
|
-
Logger.logInfo(`[ConnectionManager] Attempted to disconnect passing an undefined connection object.`);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
156
|
-
if (!connectionMetadata) {
|
|
157
|
-
Logger.logInfo(`[ConnectionManager] Attempted to disconnect but no connection was found.`);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
// Removes the callback from the connection's callbacks map.
|
|
161
|
-
connectionMetadata.callbacks.delete(connection.callbackID);
|
|
162
|
-
// If the connection's callbacks map is empty we can safely unsubscribe from the Onyx key.
|
|
163
|
-
if (connectionMetadata.callbacks.size === 0) {
|
|
164
|
-
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
165
|
-
this.connectionsMap.delete(connection.id);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Disconnect all subscribers from Onyx.
|
|
170
|
-
*/
|
|
171
|
-
disconnectAll() {
|
|
172
|
-
for (const connectionMetadata of this.connectionsMap.values()) {
|
|
173
|
-
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
174
|
-
}
|
|
175
|
-
this.connectionsMap.clear();
|
|
176
|
-
// Clear snapshot cache when all connections are disconnected
|
|
177
|
-
OnyxSnapshotCache_1.default.clear();
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Refreshes the connection manager's session ID.
|
|
181
|
-
*/
|
|
182
|
-
refreshSessionID() {
|
|
183
|
-
this.sessionID = Str.guid();
|
|
184
|
-
// Clear snapshot cache when session refreshes to avoid stale cache issues
|
|
185
|
-
OnyxSnapshotCache_1.default.clear();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
const connectionManager = new OnyxConnectionManager();
|
|
189
|
-
exports.default = connectionManager;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { OnyxKey, OnyxValue } from './types';
|
|
2
|
-
import type { UseOnyxOptions, UseOnyxResult, UseOnyxSelector } from './useOnyx';
|
|
3
|
-
/**
|
|
4
|
-
* Manages snapshot caching for useOnyx hook performance optimization.
|
|
5
|
-
* Handles selector function tracking and memoized getSnapshot results.
|
|
6
|
-
*/
|
|
7
|
-
declare class OnyxSnapshotCache {
|
|
8
|
-
/**
|
|
9
|
-
* Snapshot cache is a two-level map. The top-level keys are Onyx keys. The top-level values maps.
|
|
10
|
-
* The second-level keys are a custom composite string defined by this.registerConsumer. These represent a unique useOnyx config, which is not fully represented by the Onyx key alone.
|
|
11
|
-
* The reason we have two levels is for performance: not to make cache access faster, but to make cache invalidation faster.
|
|
12
|
-
* We can invalidate the snapshot cache for a given Onyx key with one map.delete operation on the top-level map, rather than having to loop through a large single-level map and delete any matching keys.
|
|
13
|
-
*/
|
|
14
|
-
private snapshotCache;
|
|
15
|
-
/**
|
|
16
|
-
* Maps selector functions to unique IDs for cache key generation
|
|
17
|
-
*/
|
|
18
|
-
private selectorIDMap;
|
|
19
|
-
/**
|
|
20
|
-
* Counter for generating incremental selector IDs
|
|
21
|
-
*/
|
|
22
|
-
private selectorIDCounter;
|
|
23
|
-
/**
|
|
24
|
-
* Reference counting for cache keys to enable automatic cleanup.
|
|
25
|
-
* Maps cache key (string) to number of consumers using it.
|
|
26
|
-
*/
|
|
27
|
-
private cacheKeyRefCounts;
|
|
28
|
-
constructor();
|
|
29
|
-
/**
|
|
30
|
-
* Generate unique ID for selector functions using incrementing numbers
|
|
31
|
-
*/
|
|
32
|
-
getSelectorID<TKey extends OnyxKey, TReturnValue>(selector: UseOnyxSelector<TKey, TReturnValue>): number;
|
|
33
|
-
/**
|
|
34
|
-
* Register a consumer for a cache key and return the cache key.
|
|
35
|
-
* Generates cache key and increments reference counter.
|
|
36
|
-
*
|
|
37
|
-
* The properties used to generate the cache key are handpicked for performance reasons and
|
|
38
|
-
* according to their purpose and effect they produce in the useOnyx hook behavior:
|
|
39
|
-
*
|
|
40
|
-
* - `selector`: Different selectors produce different results, so each selector needs its own cache entry
|
|
41
|
-
*
|
|
42
|
-
* Other options like `reuseConnection` don't affect the data transformation
|
|
43
|
-
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
|
|
44
|
-
*/
|
|
45
|
-
registerConsumer<TKey extends OnyxKey, TReturnValue>(key: TKey, options: Pick<UseOnyxOptions<TKey, TReturnValue>, 'selector'>): string;
|
|
46
|
-
/**
|
|
47
|
-
* Deregister a consumer for a cache key.
|
|
48
|
-
* Decrements reference counter and removes cache entry if no consumers remain.
|
|
49
|
-
*/
|
|
50
|
-
deregisterConsumer(key: OnyxKey, cacheKey: string): void;
|
|
51
|
-
/**
|
|
52
|
-
* Get cached snapshot result for a key and cache key combination
|
|
53
|
-
*/
|
|
54
|
-
getCachedResult<TResult extends UseOnyxResult<OnyxValue<OnyxKey>>>(key: OnyxKey, cacheKey: string): TResult | undefined;
|
|
55
|
-
/**
|
|
56
|
-
* Set cached snapshot result for a key and cache key combination
|
|
57
|
-
*/
|
|
58
|
-
setCachedResult<TResult extends UseOnyxResult<OnyxValue<OnyxKey>>>(key: OnyxKey, cacheKey: string, result: TResult): void;
|
|
59
|
-
/**
|
|
60
|
-
* Selective cache invalidation to prevent data unavailability
|
|
61
|
-
* Collection members invalidate upward, collections don't cascade downward
|
|
62
|
-
*/
|
|
63
|
-
invalidateForKey(keyToInvalidate: OnyxKey): void;
|
|
64
|
-
/**
|
|
65
|
-
* Clear all snapshot cache
|
|
66
|
-
*/
|
|
67
|
-
clear(): void;
|
|
68
|
-
/**
|
|
69
|
-
* Clear selector ID mappings (useful for testing)
|
|
70
|
-
*/
|
|
71
|
-
clearSelectorIds(): void;
|
|
72
|
-
}
|
|
73
|
-
declare const onyxSnapshotCache: OnyxSnapshotCache;
|
|
74
|
-
export default onyxSnapshotCache;
|
|
75
|
-
export { OnyxSnapshotCache };
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.OnyxSnapshotCache = void 0;
|
|
7
|
-
const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
|
|
8
|
-
/**
|
|
9
|
-
* Manages snapshot caching for useOnyx hook performance optimization.
|
|
10
|
-
* Handles selector function tracking and memoized getSnapshot results.
|
|
11
|
-
*/
|
|
12
|
-
class OnyxSnapshotCache {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.snapshotCache = new Map();
|
|
15
|
-
this.selectorIDMap = new WeakMap();
|
|
16
|
-
this.selectorIDCounter = 0;
|
|
17
|
-
this.cacheKeyRefCounts = new Map();
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Generate unique ID for selector functions using incrementing numbers
|
|
21
|
-
*/
|
|
22
|
-
getSelectorID(selector) {
|
|
23
|
-
const typedSelector = selector;
|
|
24
|
-
const existingID = this.selectorIDMap.get(typedSelector);
|
|
25
|
-
if (existingID !== undefined) {
|
|
26
|
-
return existingID;
|
|
27
|
-
}
|
|
28
|
-
const id = this.selectorIDCounter++;
|
|
29
|
-
this.selectorIDMap.set(typedSelector, id);
|
|
30
|
-
return id;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Register a consumer for a cache key and return the cache key.
|
|
34
|
-
* Generates cache key and increments reference counter.
|
|
35
|
-
*
|
|
36
|
-
* The properties used to generate the cache key are handpicked for performance reasons and
|
|
37
|
-
* according to their purpose and effect they produce in the useOnyx hook behavior:
|
|
38
|
-
*
|
|
39
|
-
* - `selector`: Different selectors produce different results, so each selector needs its own cache entry
|
|
40
|
-
*
|
|
41
|
-
* Other options like `reuseConnection` don't affect the data transformation
|
|
42
|
-
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
|
|
43
|
-
*/
|
|
44
|
-
registerConsumer(key, options) {
|
|
45
|
-
var _a;
|
|
46
|
-
const selectorID = (options === null || options === void 0 ? void 0 : options.selector) ? this.getSelectorID(options.selector) : 'no_selector';
|
|
47
|
-
const cacheKey = `${key}_${selectorID}`;
|
|
48
|
-
// Increment reference count for this cache key
|
|
49
|
-
const currentCount = (_a = this.cacheKeyRefCounts.get(cacheKey)) !== null && _a !== void 0 ? _a : 0;
|
|
50
|
-
this.cacheKeyRefCounts.set(cacheKey, currentCount + 1);
|
|
51
|
-
return cacheKey;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Deregister a consumer for a cache key.
|
|
55
|
-
* Decrements reference counter and removes cache entry if no consumers remain.
|
|
56
|
-
*/
|
|
57
|
-
deregisterConsumer(key, cacheKey) {
|
|
58
|
-
var _a;
|
|
59
|
-
const currentCount = (_a = this.cacheKeyRefCounts.get(cacheKey)) !== null && _a !== void 0 ? _a : 0;
|
|
60
|
-
if (currentCount <= 1) {
|
|
61
|
-
// Last consumer - remove from reference counter and cache
|
|
62
|
-
this.cacheKeyRefCounts.delete(cacheKey);
|
|
63
|
-
// Remove from snapshot cache
|
|
64
|
-
const keyCache = this.snapshotCache.get(key);
|
|
65
|
-
if (keyCache) {
|
|
66
|
-
keyCache.delete(cacheKey);
|
|
67
|
-
// If this was the last cache entry for this Onyx key, remove the key entirely
|
|
68
|
-
if (keyCache.size === 0) {
|
|
69
|
-
this.snapshotCache.delete(key);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
// Still has other consumers - just decrement count
|
|
75
|
-
this.cacheKeyRefCounts.set(cacheKey, currentCount - 1);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Get cached snapshot result for a key and cache key combination
|
|
80
|
-
*/
|
|
81
|
-
getCachedResult(key, cacheKey) {
|
|
82
|
-
const keyCache = this.snapshotCache.get(key);
|
|
83
|
-
return keyCache === null || keyCache === void 0 ? void 0 : keyCache.get(cacheKey);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Set cached snapshot result for a key and cache key combination
|
|
87
|
-
*/
|
|
88
|
-
setCachedResult(key, cacheKey, result) {
|
|
89
|
-
let keyCache = this.snapshotCache.get(key);
|
|
90
|
-
if (!keyCache) {
|
|
91
|
-
keyCache = new Map();
|
|
92
|
-
this.snapshotCache.set(key, keyCache);
|
|
93
|
-
}
|
|
94
|
-
keyCache.set(cacheKey, result);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Selective cache invalidation to prevent data unavailability
|
|
98
|
-
* Collection members invalidate upward, collections don't cascade downward
|
|
99
|
-
*/
|
|
100
|
-
invalidateForKey(keyToInvalidate) {
|
|
101
|
-
// Always invalidate the exact key
|
|
102
|
-
this.snapshotCache.delete(keyToInvalidate);
|
|
103
|
-
// Check if the key is a collection member and invalidate the collection base key
|
|
104
|
-
const collectionBaseKey = OnyxKeys_1.default.getCollectionKey(keyToInvalidate);
|
|
105
|
-
if (collectionBaseKey) {
|
|
106
|
-
this.snapshotCache.delete(collectionBaseKey);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Clear all snapshot cache
|
|
111
|
-
*/
|
|
112
|
-
clear() {
|
|
113
|
-
this.snapshotCache.clear();
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Clear selector ID mappings (useful for testing)
|
|
117
|
-
*/
|
|
118
|
-
clearSelectorIds() {
|
|
119
|
-
this.selectorIDCounter = 0;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
exports.OnyxSnapshotCache = OnyxSnapshotCache;
|
|
123
|
-
// Create and export a singleton instance
|
|
124
|
-
const onyxSnapshotCache = new OnyxSnapshotCache();
|
|
125
|
-
exports.default = onyxSnapshotCache;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wraps a selector function so that:
|
|
3
|
-
* - Calling the wrapper with the same input reference twice short-circuits to the cached output
|
|
4
|
-
* (cheap `===` check, no recompute).
|
|
5
|
-
* - Calling with a different input that produces a deep-equal output returns the *previous*
|
|
6
|
-
* output reference, so downstream `===` comparisons treat it as unchanged.
|
|
7
|
-
*
|
|
8
|
-
* This is the minimum needed for `useSyncExternalStore` to not loop when consumers pass
|
|
9
|
-
* inline selectors that allocate fresh objects on every call (e.g. `(e) => ({id: e?.id})`):
|
|
10
|
-
* without the deep-equal fallback, every `getSnapshot` would return a new reference and React
|
|
11
|
-
* would re-render (or throw "getSnapshot should be cached") indefinitely.
|
|
12
|
-
*
|
|
13
|
-
* Stateful by design — each call to `createMemoizedSelector` produces an independent wrapper
|
|
14
|
-
* with its own `lastInput`/`lastOutput` cache, so a wrapper must not be shared across
|
|
15
|
-
* subscriptions that can see different inputs.
|
|
16
|
-
*/
|
|
17
|
-
declare function createMemoizedSelector<TInput, TOutput>(selector: (input: TInput) => TOutput): (input: TInput) => TOutput;
|
|
18
|
-
export default createMemoizedSelector;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fast_equals_1 = require("fast-equals");
|
|
4
|
-
/**
|
|
5
|
-
* Wraps a selector function so that:
|
|
6
|
-
* - Calling the wrapper with the same input reference twice short-circuits to the cached output
|
|
7
|
-
* (cheap `===` check, no recompute).
|
|
8
|
-
* - Calling with a different input that produces a deep-equal output returns the *previous*
|
|
9
|
-
* output reference, so downstream `===` comparisons treat it as unchanged.
|
|
10
|
-
*
|
|
11
|
-
* This is the minimum needed for `useSyncExternalStore` to not loop when consumers pass
|
|
12
|
-
* inline selectors that allocate fresh objects on every call (e.g. `(e) => ({id: e?.id})`):
|
|
13
|
-
* without the deep-equal fallback, every `getSnapshot` would return a new reference and React
|
|
14
|
-
* would re-render (or throw "getSnapshot should be cached") indefinitely.
|
|
15
|
-
*
|
|
16
|
-
* Stateful by design — each call to `createMemoizedSelector` produces an independent wrapper
|
|
17
|
-
* with its own `lastInput`/`lastOutput` cache, so a wrapper must not be shared across
|
|
18
|
-
* subscriptions that can see different inputs.
|
|
19
|
-
*/
|
|
20
|
-
function createMemoizedSelector(selector) {
|
|
21
|
-
let lastInput;
|
|
22
|
-
let lastOutput;
|
|
23
|
-
let hasComputed = false;
|
|
24
|
-
return (input) => {
|
|
25
|
-
if (hasComputed && lastInput === input) {
|
|
26
|
-
return lastOutput;
|
|
27
|
-
}
|
|
28
|
-
const next = selector(input);
|
|
29
|
-
lastInput = input;
|
|
30
|
-
if (!hasComputed || !(0, fast_equals_1.deepEqual)(lastOutput, next)) {
|
|
31
|
-
lastOutput = next;
|
|
32
|
-
hasComputed = true;
|
|
33
|
-
}
|
|
34
|
-
return lastOutput;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
exports.default = createMemoizedSelector;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fast_equals_1 = require("fast-equals");
|
|
4
|
-
/**
|
|
5
|
-
* Memoizes shallowEqual verdicts by the identity of the compared objects. Onyx values are
|
|
6
|
-
* treated as immutable (merge/set replace objects, never mutate), so a (prev, next) reference
|
|
7
|
-
* pair always yields the same verdict. In the hot case — N no-selector hooks on the same big
|
|
8
|
-
* key — every hook compares the exact same two cache-owned objects, so the first hook pays for
|
|
9
|
-
* the O(keys) walk and the rest resolve in O(1). WeakMap keys make stale entries impossible to
|
|
10
|
-
* read (lookup requires holding both exact objects) and let GC reclaim them.
|
|
11
|
-
*/
|
|
12
|
-
const shallowEqualVerdicts = new WeakMap();
|
|
13
|
-
/**
|
|
14
|
-
* Identity-pair-memoized shallowEqual: same (a, b) references → cached verdict, no walk.
|
|
15
|
-
*/
|
|
16
|
-
function memoizedShallowEqual(a, b) {
|
|
17
|
-
// Only object pairs are memoizable (WeakMap keys) — anything else is O(1) to compare anyway.
|
|
18
|
-
if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {
|
|
19
|
-
return (0, fast_equals_1.shallowEqual)(a, b);
|
|
20
|
-
}
|
|
21
|
-
let verdictsForA = shallowEqualVerdicts.get(a);
|
|
22
|
-
if (!verdictsForA) {
|
|
23
|
-
verdictsForA = new WeakMap();
|
|
24
|
-
shallowEqualVerdicts.set(a, verdictsForA);
|
|
25
|
-
}
|
|
26
|
-
const cachedVerdict = verdictsForA.get(b);
|
|
27
|
-
if (cachedVerdict !== undefined) {
|
|
28
|
-
return cachedVerdict;
|
|
29
|
-
}
|
|
30
|
-
const verdict = (0, fast_equals_1.shallowEqual)(a, b);
|
|
31
|
-
verdictsForA.set(b, verdict);
|
|
32
|
-
return verdict;
|
|
33
|
-
}
|
|
34
|
-
exports.default = memoizedShallowEqual;
|