react-native-onyx
Version:
State management for React Native
120 lines (119 loc) • 4.74 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnyxSnapshotCache = void 0;
const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
/**
* Manages snapshot caching for useOnyx hook performance optimization.
* Handles selector function tracking and memoized getSnapshot results.
*/
class OnyxSnapshotCache {
constructor() {
this.snapshotCache = new Map();
this.selectorIDMap = new WeakMap();
this.selectorIDCounter = 0;
this.cacheKeyRefCounts = new Map();
}
/**
* Generate unique ID for selector functions using incrementing numbers
*/
getSelectorID(selector) {
const typedSelector = selector;
if (!this.selectorIDMap.has(typedSelector)) {
const id = this.selectorIDCounter++;
this.selectorIDMap.set(typedSelector, id);
}
return this.selectorIDMap.get(typedSelector);
}
/**
* Register a consumer for a cache key and return the cache key.
* Generates cache key and increments reference counter.
*
* The properties used to generate the cache key are handpicked for performance reasons and
* according to their purpose and effect they produce in the useOnyx hook behavior:
*
* - `selector`: Different selectors produce different results, so each selector needs its own cache entry
*
* Other options like `reuseConnection` don't affect the data transformation
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
*/
registerConsumer(key, options) {
const selectorID = (options === null || options === void 0 ? void 0 : options.selector) ? this.getSelectorID(options.selector) : 'no_selector';
const cacheKey = `${key}_${selectorID}`;
// Increment reference count for this cache key
const currentCount = this.cacheKeyRefCounts.get(cacheKey) || 0;
this.cacheKeyRefCounts.set(cacheKey, currentCount + 1);
return cacheKey;
}
/**
* Deregister a consumer for a cache key.
* Decrements reference counter and removes cache entry if no consumers remain.
*/
deregisterConsumer(key, cacheKey) {
const currentCount = this.cacheKeyRefCounts.get(cacheKey) || 0;
if (currentCount <= 1) {
// Last consumer - remove from reference counter and cache
this.cacheKeyRefCounts.delete(cacheKey);
// Remove from snapshot cache
const keyCache = this.snapshotCache.get(key);
if (keyCache) {
keyCache.delete(cacheKey);
// If this was the last cache entry for this Onyx key, remove the key entirely
if (keyCache.size === 0) {
this.snapshotCache.delete(key);
}
}
}
else {
// Still has other consumers - just decrement count
this.cacheKeyRefCounts.set(cacheKey, currentCount - 1);
}
}
/**
* Get cached snapshot result for a key and cache key combination
*/
getCachedResult(key, cacheKey) {
const keyCache = this.snapshotCache.get(key);
return keyCache === null || keyCache === void 0 ? void 0 : keyCache.get(cacheKey);
}
/**
* Set cached snapshot result for a key and cache key combination
*/
setCachedResult(key, cacheKey, result) {
if (!this.snapshotCache.has(key)) {
this.snapshotCache.set(key, new Map());
}
this.snapshotCache.get(key).set(cacheKey, result);
}
/**
* Selective cache invalidation to prevent data unavailability
* Collection members invalidate upward, collections don't cascade downward
*/
invalidateForKey(keyToInvalidate) {
// Always invalidate the exact key
this.snapshotCache.delete(keyToInvalidate);
// Check if the key is a collection member and invalidate the collection base key
const collectionBaseKey = OnyxKeys_1.default.getCollectionKey(keyToInvalidate);
if (collectionBaseKey) {
this.snapshotCache.delete(collectionBaseKey);
}
}
/**
* Clear all snapshot cache
*/
clear() {
this.snapshotCache.clear();
}
/**
* Clear selector ID mappings (useful for testing)
*/
clearSelectorIds() {
this.selectorIDCounter = 0;
}
}
exports.OnyxSnapshotCache = OnyxSnapshotCache;
// Create and export a singleton instance
const onyxSnapshotCache = new OnyxSnapshotCache();
exports.default = onyxSnapshotCache;