@shopify/flash-list 2.0.0-alpha.8 → 2.0.0-rc.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.
- package/README.md +38 -98
- package/dist/AnimatedFlashList.d.ts.map +1 -1
- package/dist/AnimatedFlashList.js +3 -3
- package/dist/AnimatedFlashList.js.map +1 -1
- package/dist/FlashList.d.ts +9 -0
- package/dist/FlashList.d.ts.map +1 -1
- package/dist/FlashList.js +20 -0
- package/dist/FlashList.js.map +1 -1
- package/dist/FlashListProps.d.ts +15 -8
- package/dist/FlashListProps.d.ts.map +1 -1
- package/dist/FlashListProps.js.map +1 -1
- package/dist/FlashListRef.d.ts +305 -0
- package/dist/FlashListRef.d.ts.map +1 -0
- package/dist/FlashListRef.js +3 -0
- package/dist/FlashListRef.js.map +1 -0
- package/dist/MasonryFlashList.js.map +1 -1
- package/dist/__tests__/RecyclerView.test.js +63 -28
- package/dist/__tests__/RecyclerView.test.js.map +1 -1
- package/dist/__tests__/RenderStackManager.test.d.ts +2 -0
- package/dist/__tests__/RenderStackManager.test.d.ts.map +1 -0
- package/dist/__tests__/RenderStackManager.test.js +486 -0
- package/dist/__tests__/RenderStackManager.test.js.map +1 -0
- package/dist/__tests__/helpers/createLayoutManager.d.ts.map +1 -1
- package/dist/__tests__/helpers/createLayoutManager.js +3 -4
- package/dist/__tests__/helpers/createLayoutManager.js.map +1 -1
- package/dist/__tests__/useUnmountAwareCallbacks.test.js +1 -1
- package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -1
- package/dist/benchmark/useFlatListBenchmark.js +8 -7
- package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
- package/dist/enableNewCore.d.ts.map +1 -1
- package/dist/enableNewCore.js +2 -1
- package/dist/enableNewCore.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/native/config/PlatformHelper.android.d.ts +2 -0
- package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.android.js +2 -0
- package/dist/native/config/PlatformHelper.android.js.map +1 -1
- package/dist/native/config/PlatformHelper.d.ts +2 -0
- package/dist/native/config/PlatformHelper.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.ios.d.ts +2 -0
- package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.ios.js +2 -0
- package/dist/native/config/PlatformHelper.ios.js.map +1 -1
- package/dist/native/config/PlatformHelper.js +2 -0
- package/dist/native/config/PlatformHelper.js.map +1 -1
- package/dist/native/config/PlatformHelper.web.d.ts +2 -0
- package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.web.js +3 -1
- package/dist/native/config/PlatformHelper.web.js.map +1 -1
- package/dist/recyclerview/RecyclerView.d.ts +2 -1
- package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerView.js +64 -37
- package/dist/recyclerview/RecyclerView.js.map +1 -1
- package/dist/recyclerview/RecyclerViewContextProvider.d.ts +6 -5
- package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
- package/dist/recyclerview/RecyclerViewManager.d.ts +21 -7
- package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerViewManager.js +105 -113
- package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
- package/dist/recyclerview/RenderStackManager.d.ts +85 -0
- package/dist/recyclerview/RenderStackManager.d.ts.map +1 -0
- package/dist/recyclerview/RenderStackManager.js +324 -0
- package/dist/recyclerview/RenderStackManager.js.map +1 -0
- package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
- package/dist/recyclerview/ViewHolder.js +5 -3
- package/dist/recyclerview/ViewHolder.js.map +1 -1
- package/dist/recyclerview/ViewHolderCollection.d.ts +3 -1
- package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
- package/dist/recyclerview/ViewHolderCollection.js +23 -8
- package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
- package/dist/recyclerview/components/ScrollAnchor.d.ts +2 -1
- package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -1
- package/dist/recyclerview/components/ScrollAnchor.js +9 -4
- package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
- package/dist/recyclerview/components/StickyHeaders.d.ts +1 -1
- package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
- package/dist/recyclerview/components/StickyHeaders.js +40 -32
- package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
- package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts +45 -1
- package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts.map +1 -1
- package/dist/recyclerview/helpers/EngagedIndicesTracker.js +79 -20
- package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -1
- package/dist/recyclerview/helpers/RenderTimeTracker.d.ts +10 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.d.ts.map +1 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.js +39 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -0
- package/dist/recyclerview/helpers/VelocityTracker.d.ts +29 -0
- package/dist/recyclerview/helpers/VelocityTracker.d.ts.map +1 -0
- package/dist/recyclerview/helpers/VelocityTracker.js +70 -0
- package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -0
- package/dist/recyclerview/hooks/useBoundDetection.d.ts +1 -2
- package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useBoundDetection.js +19 -16
- package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
- package/dist/recyclerview/hooks/useMappingHelper.d.ts +1 -1
- package/dist/recyclerview/hooks/useMappingHelper.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useMappingHelper.js +1 -1
- package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -1
- package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useOnLoad.js +4 -6
- package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +3 -48
- package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewController.js +179 -119
- package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts +2 -0
- package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.js +10 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
- package/dist/recyclerview/hooks/useSecondaryProps.js +1 -1
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +10 -3
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +33 -4
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +6 -0
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.js +27 -5
- package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts +10 -16
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.js +4 -14
- package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +2 -2
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -1
- package/dist/recyclerview/utils/measureLayout.d.ts +1 -29
- package/dist/recyclerview/utils/measureLayout.d.ts.map +1 -1
- package/dist/recyclerview/utils/measureLayout.js +2 -4
- package/dist/recyclerview/utils/measureLayout.js.map +1 -1
- package/dist/recyclerview/utils/measureLayout.web.d.ts +29 -0
- package/dist/recyclerview/utils/measureLayout.web.d.ts.map +1 -0
- package/dist/recyclerview/utils/measureLayout.web.js +89 -0
- package/dist/recyclerview/utils/measureLayout.web.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/viewability/ViewToken.d.ts +2 -2
- package/dist/viewability/ViewToken.d.ts.map +1 -1
- package/dist/viewability/ViewabilityHelper.js +1 -1
- package/dist/viewability/ViewabilityHelper.js.map +1 -1
- package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
- package/dist/viewability/ViewabilityManager.js +1 -2
- package/dist/viewability/ViewabilityManager.js.map +1 -1
- package/jestSetup.js +30 -11
- package/package.json +2 -1
- package/src/AnimatedFlashList.ts +3 -2
- package/src/FlashList.tsx +24 -0
- package/src/FlashListProps.ts +20 -8
- package/src/FlashListRef.ts +320 -0
- package/src/MasonryFlashList.tsx +2 -2
- package/src/__tests__/RecyclerView.test.tsx +84 -30
- package/src/__tests__/RenderStackManager.test.ts +575 -0
- package/src/__tests__/helpers/createLayoutManager.ts +2 -3
- package/src/__tests__/useUnmountAwareCallbacks.test.tsx +12 -12
- package/src/benchmark/useFlatListBenchmark.ts +2 -2
- package/src/enableNewCore.ts +3 -1
- package/src/index.ts +1 -0
- package/src/native/config/PlatformHelper.android.ts +2 -0
- package/src/native/config/PlatformHelper.ios.ts +2 -0
- package/src/native/config/PlatformHelper.ts +2 -0
- package/src/native/config/PlatformHelper.web.ts +3 -1
- package/src/recyclerview/RecyclerView.tsx +85 -43
- package/src/recyclerview/RecyclerViewContextProvider.ts +12 -6
- package/src/recyclerview/RecyclerViewManager.ts +123 -98
- package/src/recyclerview/RenderStackManager.ts +291 -0
- package/src/recyclerview/ViewHolder.tsx +5 -3
- package/src/recyclerview/ViewHolderCollection.tsx +33 -12
- package/src/recyclerview/components/ScrollAnchor.tsx +21 -8
- package/src/recyclerview/components/StickyHeaders.tsx +63 -44
- package/src/recyclerview/helpers/EngagedIndicesTracker.ts +120 -23
- package/src/recyclerview/helpers/RenderTimeTracker.ts +38 -0
- package/src/recyclerview/helpers/VelocityTracker.ts +77 -0
- package/src/recyclerview/hooks/useBoundDetection.ts +25 -18
- package/src/recyclerview/hooks/useMappingHelper.ts +1 -1
- package/src/recyclerview/hooks/useOnLoad.ts +4 -6
- package/src/recyclerview/hooks/useRecyclerViewController.tsx +204 -173
- package/src/recyclerview/hooks/useRecyclerViewManager.ts +11 -1
- package/src/recyclerview/hooks/useSecondaryProps.tsx +1 -1
- package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +39 -3
- package/src/recyclerview/layout-managers/GridLayoutManager.ts +30 -7
- package/src/recyclerview/layout-managers/LayoutManager.ts +12 -21
- package/src/recyclerview/layout-managers/MasonryLayoutManager.ts +1 -1
- package/src/recyclerview/utils/measureLayout.ts +3 -3
- package/src/recyclerview/utils/measureLayout.web.ts +104 -0
- package/src/viewability/ViewToken.ts +2 -2
- package/src/viewability/ViewabilityHelper.ts +1 -1
- package/src/viewability/ViewabilityManager.ts +6 -3
- package/dist/__tests__/RecycleKeyManager.test.d.ts +0 -2
- package/dist/__tests__/RecycleKeyManager.test.d.ts.map +0 -1
- package/dist/__tests__/RecycleKeyManager.test.js +0 -210
- package/dist/__tests__/RecycleKeyManager.test.js.map +0 -1
- package/dist/recyclerview/RecycleKeyManager.d.ts +0 -82
- package/dist/recyclerview/RecycleKeyManager.d.ts.map +0 -1
- package/dist/recyclerview/RecycleKeyManager.js +0 -135
- package/dist/recyclerview/RecycleKeyManager.js.map +0 -1
- package/src/__tests__/RecycleKeyManager.test.ts +0 -254
- package/src/recyclerview/RecycleKeyManager.ts +0 -185
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
export interface RecycleKeyManager {
|
|
2
|
-
/**
|
|
3
|
-
* Retrieves a unique key for an item type, maintaining a separate pool for each type.
|
|
4
|
-
* If a stableId is provided and exists, returns the associated key.
|
|
5
|
-
* Otherwise, generates a new key or reuses one from the pool.
|
|
6
|
-
* @param itemType - The type/category of the item (e.g., 'header', 'product', 'footer')
|
|
7
|
-
* @param stableId - Optional unique identifier for stable item tracking
|
|
8
|
-
* @param currentKey - Optional current key to maintain if it exists in the pool
|
|
9
|
-
* @returns A unique key for the item
|
|
10
|
-
*/
|
|
11
|
-
getKey: (itemType: string, stableId: string, currentKey?: string) => string;
|
|
12
|
-
/**
|
|
13
|
-
* Recycles a key back into its item type's pool when the associated view is no longer visible.
|
|
14
|
-
* This allows the key to be reused for new items of the same type.
|
|
15
|
-
* @param key - The key to be recycled back into the pool
|
|
16
|
-
*/
|
|
17
|
-
recycleKey: (key: string) => void;
|
|
18
|
-
/**
|
|
19
|
-
* Checks if a key is currently available in the recycling pool (not in use).
|
|
20
|
-
* @param key - The key to check
|
|
21
|
-
* @returns True if the key is available in the pool, false otherwise
|
|
22
|
-
*/
|
|
23
|
-
hasKeyInPool: (key: string) => boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Clears all recycled keys from the pool, resetting the recycling system.
|
|
26
|
-
* This is useful when the list needs to be completely reset.
|
|
27
|
-
*/
|
|
28
|
-
clearPool: () => void;
|
|
29
|
-
}
|
|
30
|
-
export declare class RecycleKeyManagerImpl implements RecycleKeyManager {
|
|
31
|
-
private maxItems;
|
|
32
|
-
private keyPools;
|
|
33
|
-
private keyMap;
|
|
34
|
-
private stableIdMap;
|
|
35
|
-
private keyCounter;
|
|
36
|
-
/**
|
|
37
|
-
* Creates a new RecycleKeyManager with a specified maximum number of items.
|
|
38
|
-
* @param maxItems - Maximum number of unique keys that can be active simultaneously.
|
|
39
|
-
* Defaults to Number.MAX_SAFE_INTEGER if not specified.
|
|
40
|
-
*/
|
|
41
|
-
constructor(maxItems?: number);
|
|
42
|
-
/**
|
|
43
|
-
* Gets a key for the specified item type, prioritizing stable ID associations.
|
|
44
|
-
* If a stable ID exists, returns its associated key. Otherwise, either reuses
|
|
45
|
-
* a key from the pool or generates a new one.
|
|
46
|
-
* @param itemType - The type/category of the item
|
|
47
|
-
* @param stableId - Optional unique identifier for stable item tracking
|
|
48
|
-
* @param currentKey - Optional current key to maintain if it exists in the pool
|
|
49
|
-
* @returns A unique key for the item
|
|
50
|
-
*/
|
|
51
|
-
getKey(itemType: string, stableId: string, currentKey?: string): string;
|
|
52
|
-
/**
|
|
53
|
-
* Recycles a key by adding it back to its item type's pool and cleaning up
|
|
54
|
-
* associated mappings. This should be called when a view is no longer visible.
|
|
55
|
-
* @param key - The key to be recycled
|
|
56
|
-
*/
|
|
57
|
-
recycleKey(key: string): void;
|
|
58
|
-
/**
|
|
59
|
-
* Checks if a key is currently available in the recycling pool.
|
|
60
|
-
* @param key - The key to check
|
|
61
|
-
* @returns True if the key is available in the pool, false otherwise
|
|
62
|
-
*/
|
|
63
|
-
hasKeyInPool(key: string): boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Clears all recycled keys from the pool, effectively resetting the recycling system.
|
|
66
|
-
* This operation does not affect currently active keys.
|
|
67
|
-
*/
|
|
68
|
-
clearPool(): void;
|
|
69
|
-
/**
|
|
70
|
-
* Generates a unique sequential key using an internal counter.
|
|
71
|
-
* @returns A unique key as a string
|
|
72
|
-
*/
|
|
73
|
-
private generateKey;
|
|
74
|
-
/**
|
|
75
|
-
* Ensures the total number of active keys doesn't exceed the maximum limit.
|
|
76
|
-
* If the limit is exceeded, recycles the oldest keys until within bounds.
|
|
77
|
-
* Note: This operation may impact performance when dealing with large lists.
|
|
78
|
-
* TODO: Check performance impact of this
|
|
79
|
-
*/
|
|
80
|
-
private ensurePoolSize;
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=RecycleKeyManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RecycleKeyManager.d.ts","sourceRoot":"","sources":["../../src/recyclerview/RecycleKeyManager.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAE5E;;;;OAIG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;;;OAIG;IACH,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvC;;;OAGG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,qBAAa,qBAAsB,YAAW,iBAAiB;IAE7D,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,QAAQ,CAA2B;IAG3C,OAAO,CAAC,MAAM,CAAuD;IAGrE,OAAO,CAAC,WAAW,CAAsB;IAGzC,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;OAIG;gBACS,QAAQ,GAAE,MAAgC;IAQtD;;;;;;;;OAQG;IACI,MAAM,CACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM;IAsCT;;;;OAIG;IACI,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAwBpC;;;;OAIG;IACI,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzC;;;OAGG;IACI,SAAS;IAIhB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAInB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;CAWvB"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RecycleKeyManagerImpl = void 0;
|
|
4
|
-
var tslib_1 = require("tslib");
|
|
5
|
-
var RecycleKeyManagerImpl = /** @class */ (function () {
|
|
6
|
-
/**
|
|
7
|
-
* Creates a new RecycleKeyManager with a specified maximum number of items.
|
|
8
|
-
* @param maxItems - Maximum number of unique keys that can be active simultaneously.
|
|
9
|
-
* Defaults to Number.MAX_SAFE_INTEGER if not specified.
|
|
10
|
-
*/
|
|
11
|
-
function RecycleKeyManagerImpl(maxItems) {
|
|
12
|
-
if (maxItems === void 0) { maxItems = Number.MAX_SAFE_INTEGER; }
|
|
13
|
-
this.maxItems = maxItems;
|
|
14
|
-
this.keyPools = new Map();
|
|
15
|
-
this.keyMap = new Map();
|
|
16
|
-
this.stableIdMap = new Map();
|
|
17
|
-
this.keyCounter = 0;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Gets a key for the specified item type, prioritizing stable ID associations.
|
|
21
|
-
* If a stable ID exists, returns its associated key. Otherwise, either reuses
|
|
22
|
-
* a key from the pool or generates a new one.
|
|
23
|
-
* @param itemType - The type/category of the item
|
|
24
|
-
* @param stableId - Optional unique identifier for stable item tracking
|
|
25
|
-
* @param currentKey - Optional current key to maintain if it exists in the pool
|
|
26
|
-
* @returns A unique key for the item
|
|
27
|
-
*/
|
|
28
|
-
RecycleKeyManagerImpl.prototype.getKey = function (itemType, stableId, currentKey) {
|
|
29
|
-
// Return existing key if stableId is already mapped
|
|
30
|
-
if (stableId && this.stableIdMap.has(stableId)) {
|
|
31
|
-
return this.stableIdMap.get(stableId);
|
|
32
|
-
}
|
|
33
|
-
// Get or create the pool for this item type
|
|
34
|
-
var pool = this.keyPools.get(itemType);
|
|
35
|
-
if (!pool) {
|
|
36
|
-
pool = new Set();
|
|
37
|
-
this.keyPools.set(itemType, pool);
|
|
38
|
-
}
|
|
39
|
-
var key;
|
|
40
|
-
// Reuse existing key from pool if available
|
|
41
|
-
if (pool.size > 0) {
|
|
42
|
-
key =
|
|
43
|
-
currentKey && pool.has(currentKey)
|
|
44
|
-
? currentKey
|
|
45
|
-
: pool.values().next().value;
|
|
46
|
-
pool.delete(key);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// Generate new key if pool is empty
|
|
50
|
-
key = this.generateKey();
|
|
51
|
-
}
|
|
52
|
-
// Update mappings with new key information
|
|
53
|
-
this.keyMap.set(key, { itemType: itemType, stableId: stableId });
|
|
54
|
-
if (stableId) {
|
|
55
|
-
this.stableIdMap.set(stableId, key);
|
|
56
|
-
}
|
|
57
|
-
// Ensure we don't exceed the maximum number of active keys
|
|
58
|
-
this.ensurePoolSize();
|
|
59
|
-
return key;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Recycles a key by adding it back to its item type's pool and cleaning up
|
|
63
|
-
* associated mappings. This should be called when a view is no longer visible.
|
|
64
|
-
* @param key - The key to be recycled
|
|
65
|
-
*/
|
|
66
|
-
RecycleKeyManagerImpl.prototype.recycleKey = function (key) {
|
|
67
|
-
var keyInfo = this.keyMap.get(key);
|
|
68
|
-
if (!keyInfo) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
var itemType = keyInfo.itemType, stableId = keyInfo.stableId;
|
|
72
|
-
// Clean up stable ID mapping if it exists
|
|
73
|
-
if (stableId) {
|
|
74
|
-
this.stableIdMap.delete(stableId);
|
|
75
|
-
}
|
|
76
|
-
// Add key back to its type's pool
|
|
77
|
-
var pool = this.keyPools.get(itemType);
|
|
78
|
-
if (!pool) {
|
|
79
|
-
pool = new Set();
|
|
80
|
-
this.keyPools.set(itemType, pool);
|
|
81
|
-
}
|
|
82
|
-
pool.add(key);
|
|
83
|
-
this.keyMap.delete(key);
|
|
84
|
-
};
|
|
85
|
-
/**
|
|
86
|
-
* Checks if a key is currently available in the recycling pool.
|
|
87
|
-
* @param key - The key to check
|
|
88
|
-
* @returns True if the key is available in the pool, false otherwise
|
|
89
|
-
*/
|
|
90
|
-
RecycleKeyManagerImpl.prototype.hasKeyInPool = function (key) {
|
|
91
|
-
return !this.keyMap.has(key);
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
* Clears all recycled keys from the pool, effectively resetting the recycling system.
|
|
95
|
-
* This operation does not affect currently active keys.
|
|
96
|
-
*/
|
|
97
|
-
RecycleKeyManagerImpl.prototype.clearPool = function () {
|
|
98
|
-
this.keyPools.clear();
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Generates a unique sequential key using an internal counter.
|
|
102
|
-
* @returns A unique key as a string
|
|
103
|
-
*/
|
|
104
|
-
RecycleKeyManagerImpl.prototype.generateKey = function () {
|
|
105
|
-
return (this.keyCounter++).toString();
|
|
106
|
-
};
|
|
107
|
-
/**
|
|
108
|
-
* Ensures the total number of active keys doesn't exceed the maximum limit.
|
|
109
|
-
* If the limit is exceeded, recycles the oldest keys until within bounds.
|
|
110
|
-
* Note: This operation may impact performance when dealing with large lists.
|
|
111
|
-
* TODO: Check performance impact of this
|
|
112
|
-
*/
|
|
113
|
-
RecycleKeyManagerImpl.prototype.ensurePoolSize = function () {
|
|
114
|
-
var e_1, _a;
|
|
115
|
-
if (this.keyMap.size <= this.maxItems)
|
|
116
|
-
return;
|
|
117
|
-
var keysToRecycle = Array.from(this.keyMap.keys()).slice(0, this.keyMap.size - this.maxItems);
|
|
118
|
-
try {
|
|
119
|
-
for (var keysToRecycle_1 = tslib_1.__values(keysToRecycle), keysToRecycle_1_1 = keysToRecycle_1.next(); !keysToRecycle_1_1.done; keysToRecycle_1_1 = keysToRecycle_1.next()) {
|
|
120
|
-
var key = keysToRecycle_1_1.value;
|
|
121
|
-
this.recycleKey(key);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
125
|
-
finally {
|
|
126
|
-
try {
|
|
127
|
-
if (keysToRecycle_1_1 && !keysToRecycle_1_1.done && (_a = keysToRecycle_1.return)) _a.call(keysToRecycle_1);
|
|
128
|
-
}
|
|
129
|
-
finally { if (e_1) throw e_1.error; }
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
return RecycleKeyManagerImpl;
|
|
133
|
-
}());
|
|
134
|
-
exports.RecycleKeyManagerImpl = RecycleKeyManagerImpl;
|
|
135
|
-
//# sourceMappingURL=RecycleKeyManager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RecycleKeyManager.js","sourceRoot":"","sources":["../../src/recyclerview/RecycleKeyManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { RecycleKeyManagerImpl } from "../recyclerview/RecycleKeyManager";
|
|
2
|
-
|
|
3
|
-
describe("RecycleKeyManagerImpl", () => {
|
|
4
|
-
let keyManager: RecycleKeyManagerImpl;
|
|
5
|
-
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
// Initialize a new manager before each test
|
|
8
|
-
keyManager = new RecycleKeyManagerImpl();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
describe("constructor", () => {
|
|
12
|
-
it("should initialize with default maxItems", () => {
|
|
13
|
-
// Test default maxItems value (implicitly tested via other methods)
|
|
14
|
-
// We can potentially expose maxItems for testing or test its effect
|
|
15
|
-
expect(keyManager).toBeDefined(); // Basic check
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("should initialize with specified maxItems", () => {
|
|
19
|
-
const specificMaxItems = 10;
|
|
20
|
-
keyManager = new RecycleKeyManagerImpl(specificMaxItems);
|
|
21
|
-
// Test the effect of maxItems limit later in getKey tests
|
|
22
|
-
expect(keyManager).toBeDefined(); // Basic check
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe("getKey", () => {
|
|
27
|
-
it("should generate a new key for a new item type without stableId", () => {
|
|
28
|
-
const key = keyManager.getKey("typeA", "item1");
|
|
29
|
-
expect(key).toBeDefined();
|
|
30
|
-
expect(typeof key).toBe("string");
|
|
31
|
-
expect(keyManager.hasKeyInPool(key)).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("should generate a different key for a different item type", () => {
|
|
35
|
-
const keyA = keyManager.getKey("typeA", "item1");
|
|
36
|
-
const keyB = keyManager.getKey("typeB", "item2");
|
|
37
|
-
expect(keyA).not.toEqual(keyB);
|
|
38
|
-
expect(keyManager.hasKeyInPool(keyA)).toBe(false);
|
|
39
|
-
expect(keyManager.hasKeyInPool(keyB)).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("should generate sequential keys when pool is empty", () => {
|
|
43
|
-
const key1 = keyManager.getKey("typeA", "item1");
|
|
44
|
-
const key2 = keyManager.getKey("typeA", "item2");
|
|
45
|
-
expect(parseInt(key2, 10)).toBe(parseInt(key1, 10) + 1);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("should return the existing key for a known stableId", () => {
|
|
49
|
-
const stableId = "stable1";
|
|
50
|
-
const key1 = keyManager.getKey("typeA", stableId);
|
|
51
|
-
const key2 = keyManager.getKey("typeA", stableId);
|
|
52
|
-
const key3 = keyManager.getKey("typeB", stableId); // Different type, same stableId
|
|
53
|
-
expect(key2).toEqual(key1);
|
|
54
|
-
expect(key3).toEqual(key1); // Should still return the key associated with the stableId
|
|
55
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(false);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("should reuse a key from the pool for the same item type", () => {
|
|
59
|
-
const key1 = keyManager.getKey("typeA", "item1");
|
|
60
|
-
keyManager.recycleKey(key1);
|
|
61
|
-
const key2 = keyManager.getKey("typeA", "item2");
|
|
62
|
-
expect(key2).toEqual(key1); // Should reuse the recycled key
|
|
63
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("should reuse the specified currentKey if it exists in the pool", () => {
|
|
67
|
-
const key1 = keyManager.getKey("typeA", "item1");
|
|
68
|
-
const key2 = keyManager.getKey("typeA", "item2");
|
|
69
|
-
keyManager.recycleKey(key1);
|
|
70
|
-
keyManager.recycleKey(key2);
|
|
71
|
-
|
|
72
|
-
const reusedKey = keyManager.getKey("typeA", "item3", key1);
|
|
73
|
-
expect(reusedKey).toEqual(key1);
|
|
74
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(false);
|
|
75
|
-
// key2 should still be in the pool
|
|
76
|
-
expect(keyManager.hasKeyInPool(key2)).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("should reuse any key from the pool if currentKey does not exist", () => {
|
|
80
|
-
const key1 = keyManager.getKey("typeA", "item1");
|
|
81
|
-
const key2 = keyManager.getKey("typeA", "item2");
|
|
82
|
-
keyManager.recycleKey(key1);
|
|
83
|
-
keyManager.recycleKey(key2);
|
|
84
|
-
|
|
85
|
-
const nonExistentKey = "nonExistentKey";
|
|
86
|
-
const reusedKey = keyManager.getKey("typeA", "item3", nonExistentKey);
|
|
87
|
-
|
|
88
|
-
// It should have reused either key1 or key2
|
|
89
|
-
expect([key1, key2]).toContain(reusedKey);
|
|
90
|
-
expect(keyManager.hasKeyInPool(reusedKey)).toBe(false);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("should prioritize stableId over pool reuse", () => {
|
|
94
|
-
const stableId = "stable1";
|
|
95
|
-
const key1 = keyManager.getKey("typeA", stableId); // Assign key1 to stable1
|
|
96
|
-
const key2 = keyManager.getKey("typeA", "item2");
|
|
97
|
-
keyManager.recycleKey(key2); // Put key2 in the pool
|
|
98
|
-
|
|
99
|
-
// Request key for stable1 again
|
|
100
|
-
const key3 = keyManager.getKey("typeA", stableId);
|
|
101
|
-
expect(key3).toEqual(key1); // Should return key1 associated with stableId
|
|
102
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(false);
|
|
103
|
-
// key2 should still be in the pool
|
|
104
|
-
expect(keyManager.hasKeyInPool(key2)).toBe(true);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("should assign stableId to a reused key", () => {
|
|
108
|
-
const key1 = keyManager.getKey("typeA", "item1");
|
|
109
|
-
keyManager.recycleKey(key1);
|
|
110
|
-
|
|
111
|
-
const stableId = "stableReuse";
|
|
112
|
-
const reusedKey = keyManager.getKey("typeA", stableId); // Reuse key1 and assign stableId
|
|
113
|
-
expect(reusedKey).toEqual(key1);
|
|
114
|
-
|
|
115
|
-
// Verify stableId mapping
|
|
116
|
-
const keyForStableId = keyManager.getKey("typeA", stableId);
|
|
117
|
-
expect(keyForStableId).toEqual(key1);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should handle ensurePoolSize when maxItems is exceeded", () => {
|
|
121
|
-
const maxItems = 2;
|
|
122
|
-
keyManager = new RecycleKeyManagerImpl(maxItems);
|
|
123
|
-
|
|
124
|
-
const key1 = keyManager.getKey("typeA", "item1"); // Active: {key1}
|
|
125
|
-
const key2 = keyManager.getKey("typeA", "item2"); // Active: {key1, key2}
|
|
126
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(false);
|
|
127
|
-
expect(keyManager.hasKeyInPool(key2)).toBe(false);
|
|
128
|
-
|
|
129
|
-
// This should trigger ensurePoolSize and recycle key1 (oldest)
|
|
130
|
-
const key3 = keyManager.getKey("typeA", "item3"); // Active: {key2, key3}
|
|
131
|
-
|
|
132
|
-
expect(keyManager.hasKeyInPool(key1)).toBe(true); // key1 should be recycled
|
|
133
|
-
expect(keyManager.hasKeyInPool(key2)).toBe(false);
|
|
134
|
-
expect(keyManager.hasKeyInPool(key3)).toBe(false);
|
|
135
|
-
|
|
136
|
-
// This should trigger ensurePoolSize and recycle key2
|
|
137
|
-
const key4 = keyManager.getKey("typeA", "item4"); // Active: {key3, key4}
|
|
138
|
-
expect(keyManager.hasKeyInPool(key2)).toBe(true); // key2 should be recycled
|
|
139
|
-
expect(keyManager.hasKeyInPool(key3)).toBe(false);
|
|
140
|
-
expect(keyManager.hasKeyInPool(key4)).toBe(false);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe("recycleKey", () => {
|
|
145
|
-
it("should add the key back to the correct pool", () => {
|
|
146
|
-
const keyA = keyManager.getKey("typeA", "item1");
|
|
147
|
-
const keyB = keyManager.getKey("typeB", "item2");
|
|
148
|
-
|
|
149
|
-
expect(keyManager.hasKeyInPool(keyA)).toBe(false);
|
|
150
|
-
expect(keyManager.hasKeyInPool(keyB)).toBe(false);
|
|
151
|
-
|
|
152
|
-
keyManager.recycleKey(keyA);
|
|
153
|
-
expect(keyManager.hasKeyInPool(keyA)).toBe(true);
|
|
154
|
-
expect(keyManager.hasKeyInPool(keyB)).toBe(false); // keyB should remain active
|
|
155
|
-
|
|
156
|
-
// Verify reuse from correct pool
|
|
157
|
-
const reusedKeyA = keyManager.getKey("typeA", "item3");
|
|
158
|
-
expect(reusedKeyA).toEqual(keyA);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("should do nothing if the key does not exist or is already recycled", () => {
|
|
162
|
-
const key = keyManager.getKey("typeA", "item1");
|
|
163
|
-
keyManager.recycleKey(key); // Recycle it once
|
|
164
|
-
|
|
165
|
-
// Get current state (how many keys active, how many in pool)
|
|
166
|
-
// We need internal access or specific methods to check pool size directly.
|
|
167
|
-
// Let's assume internal state is correct after first recycle.
|
|
168
|
-
|
|
169
|
-
keyManager.recycleKey(key); // Try recycling again
|
|
170
|
-
keyManager.recycleKey("nonExistentKey"); // Try recycling non-existent key
|
|
171
|
-
|
|
172
|
-
// Verify state hasn't changed unexpectedly
|
|
173
|
-
expect(keyManager.hasKeyInPool(key)).toBe(true); // Still in pool
|
|
174
|
-
const newKey = keyManager.getKey("typeA", "item2");
|
|
175
|
-
expect(newKey).toEqual(key); // Should still reuse the original key
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe("hasKeyInPool", () => {
|
|
180
|
-
it("should return false for an active key", () => {
|
|
181
|
-
const key = keyManager.getKey("typeA", "item1");
|
|
182
|
-
expect(keyManager.hasKeyInPool(key)).toBe(false);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it("should return true for a recycled key", () => {
|
|
186
|
-
const key = keyManager.getKey("typeA", "item1");
|
|
187
|
-
keyManager.recycleKey(key);
|
|
188
|
-
expect(keyManager.hasKeyInPool(key)).toBe(true);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("should return true for a key that was never generated", () => {
|
|
192
|
-
expect(keyManager.hasKeyInPool("nonExistentKey")).toBe(true);
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe("clearPool", () => {
|
|
197
|
-
it("should clear all keys from all pools", () => {
|
|
198
|
-
const keyA1 = keyManager.getKey("typeA", "item1");
|
|
199
|
-
const keyA2 = keyManager.getKey("typeA", "item2");
|
|
200
|
-
const keyB1 = keyManager.getKey("typeB", "item3");
|
|
201
|
-
|
|
202
|
-
keyManager.recycleKey(keyA1);
|
|
203
|
-
keyManager.recycleKey(keyB1);
|
|
204
|
-
|
|
205
|
-
expect(keyManager.hasKeyInPool(keyA1)).toBe(true);
|
|
206
|
-
expect(keyManager.hasKeyInPool(keyA2)).toBe(false); // Still active
|
|
207
|
-
expect(keyManager.hasKeyInPool(keyB1)).toBe(true);
|
|
208
|
-
|
|
209
|
-
keyManager.clearPool();
|
|
210
|
-
|
|
211
|
-
expect(keyManager.hasKeyInPool(keyA1)).toBe(true); // Still not active
|
|
212
|
-
expect(keyManager.hasKeyInPool(keyB1)).toBe(true); // Still not active
|
|
213
|
-
expect(keyManager.hasKeyInPool(keyA2)).toBe(false); // Active keys remain
|
|
214
|
-
|
|
215
|
-
// Getting new keys should generate new ones, not reuse cleared ones
|
|
216
|
-
const newKeyA = keyManager.getKey("typeA", "item4");
|
|
217
|
-
const newKeyB = keyManager.getKey("typeB", "item5");
|
|
218
|
-
|
|
219
|
-
expect(newKeyA).not.toEqual(keyA1);
|
|
220
|
-
expect(newKeyB).not.toEqual(keyB1);
|
|
221
|
-
// Depending on implementation, newKeyA might be keyA1 if keyCounter wasn't reset
|
|
222
|
-
// Check if key reuse happens after clearPool -> it shouldn't reuse from the *pool*
|
|
223
|
-
const keyA3 = keyManager.getKey("typeA", "item5"); // Generate another A key
|
|
224
|
-
keyManager.recycleKey(keyA3); // Recycle it
|
|
225
|
-
keyManager.clearPool(); // Clear pools again
|
|
226
|
-
keyManager.getKey("typeA", "item6"); // Get a new key
|
|
227
|
-
expect(keyManager.hasKeyInPool(keyA3)).toBe(true); // keyA3 is not active
|
|
228
|
-
// keyA4 should be newly generated, not reused from the cleared pool
|
|
229
|
-
// Note: Due to sequential key generation, it *might* match a previous key numerically
|
|
230
|
-
// but the crucial part is it wasn't reused *from the pool*.
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it("should not affect active keys or stableId mappings", () => {
|
|
234
|
-
const stableId = "stableClear";
|
|
235
|
-
const keyA = keyManager.getKey("typeA", stableId);
|
|
236
|
-
const keyB = keyManager.getKey("typeB", "item2");
|
|
237
|
-
keyManager.recycleKey(keyB); // Put keyB in pool
|
|
238
|
-
|
|
239
|
-
expect(keyManager.hasKeyInPool(keyA)).toBe(false);
|
|
240
|
-
expect(keyManager.hasKeyInPool(keyB)).toBe(true);
|
|
241
|
-
expect(keyManager.getKey("typeA", stableId)).toEqual(keyA); // Check stableId mapping
|
|
242
|
-
|
|
243
|
-
keyManager.clearPool();
|
|
244
|
-
|
|
245
|
-
expect(keyManager.hasKeyInPool(keyA)).toBe(false); // keyA still active
|
|
246
|
-
expect(keyManager.hasKeyInPool(keyB)).toBe(true); // keyB still considered "in pool" (i.e., not active)
|
|
247
|
-
expect(keyManager.getKey("typeA", stableId)).toEqual(keyA); // StableId mapping persists
|
|
248
|
-
|
|
249
|
-
// Trying to get a key of type B should generate a new one
|
|
250
|
-
const newKeyB = keyManager.getKey("typeB", "item3");
|
|
251
|
-
expect(newKeyB).not.toEqual(keyB); // Because pool was cleared
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
});
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
export interface RecycleKeyManager {
|
|
2
|
-
/**
|
|
3
|
-
* Retrieves a unique key for an item type, maintaining a separate pool for each type.
|
|
4
|
-
* If a stableId is provided and exists, returns the associated key.
|
|
5
|
-
* Otherwise, generates a new key or reuses one from the pool.
|
|
6
|
-
* @param itemType - The type/category of the item (e.g., 'header', 'product', 'footer')
|
|
7
|
-
* @param stableId - Optional unique identifier for stable item tracking
|
|
8
|
-
* @param currentKey - Optional current key to maintain if it exists in the pool
|
|
9
|
-
* @returns A unique key for the item
|
|
10
|
-
*/
|
|
11
|
-
getKey: (itemType: string, stableId: string, currentKey?: string) => string;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Recycles a key back into its item type's pool when the associated view is no longer visible.
|
|
15
|
-
* This allows the key to be reused for new items of the same type.
|
|
16
|
-
* @param key - The key to be recycled back into the pool
|
|
17
|
-
*/
|
|
18
|
-
recycleKey: (key: string) => void;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Checks if a key is currently available in the recycling pool (not in use).
|
|
22
|
-
* @param key - The key to check
|
|
23
|
-
* @returns True if the key is available in the pool, false otherwise
|
|
24
|
-
*/
|
|
25
|
-
hasKeyInPool: (key: string) => boolean;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Clears all recycled keys from the pool, resetting the recycling system.
|
|
29
|
-
* This is useful when the list needs to be completely reset.
|
|
30
|
-
*/
|
|
31
|
-
clearPool: () => void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class RecycleKeyManagerImpl implements RecycleKeyManager {
|
|
35
|
-
// Maximum number of unique keys that can be active at any time
|
|
36
|
-
private maxItems: number;
|
|
37
|
-
|
|
38
|
-
// Stores pools of recycled keys for each item type
|
|
39
|
-
private keyPools: Map<string, Set<string>>;
|
|
40
|
-
|
|
41
|
-
// Maps active keys to their metadata (item type and stable ID)
|
|
42
|
-
private keyMap: Map<string, { itemType: string; stableId?: string }>;
|
|
43
|
-
|
|
44
|
-
// Maps stable IDs to their corresponding keys for quick lookups
|
|
45
|
-
private stableIdMap: Map<string, string>;
|
|
46
|
-
|
|
47
|
-
// Counter for generating unique sequential keys
|
|
48
|
-
private keyCounter: number;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Creates a new RecycleKeyManager with a specified maximum number of items.
|
|
52
|
-
* @param maxItems - Maximum number of unique keys that can be active simultaneously.
|
|
53
|
-
* Defaults to Number.MAX_SAFE_INTEGER if not specified.
|
|
54
|
-
*/
|
|
55
|
-
constructor(maxItems: number = Number.MAX_SAFE_INTEGER) {
|
|
56
|
-
this.maxItems = maxItems;
|
|
57
|
-
this.keyPools = new Map();
|
|
58
|
-
this.keyMap = new Map();
|
|
59
|
-
this.stableIdMap = new Map();
|
|
60
|
-
this.keyCounter = 0;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Gets a key for the specified item type, prioritizing stable ID associations.
|
|
65
|
-
* If a stable ID exists, returns its associated key. Otherwise, either reuses
|
|
66
|
-
* a key from the pool or generates a new one.
|
|
67
|
-
* @param itemType - The type/category of the item
|
|
68
|
-
* @param stableId - Optional unique identifier for stable item tracking
|
|
69
|
-
* @param currentKey - Optional current key to maintain if it exists in the pool
|
|
70
|
-
* @returns A unique key for the item
|
|
71
|
-
*/
|
|
72
|
-
public getKey(
|
|
73
|
-
itemType: string,
|
|
74
|
-
stableId: string,
|
|
75
|
-
currentKey?: string
|
|
76
|
-
): string {
|
|
77
|
-
// Return existing key if stableId is already mapped
|
|
78
|
-
if (stableId && this.stableIdMap.has(stableId)) {
|
|
79
|
-
return this.stableIdMap.get(stableId)!;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Get or create the pool for this item type
|
|
83
|
-
let pool = this.keyPools.get(itemType);
|
|
84
|
-
if (!pool) {
|
|
85
|
-
pool = new Set();
|
|
86
|
-
this.keyPools.set(itemType, pool);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let key: string;
|
|
90
|
-
// Reuse existing key from pool if available
|
|
91
|
-
if (pool.size > 0) {
|
|
92
|
-
key =
|
|
93
|
-
currentKey && pool.has(currentKey)
|
|
94
|
-
? currentKey
|
|
95
|
-
: pool.values().next().value;
|
|
96
|
-
pool.delete(key);
|
|
97
|
-
} else {
|
|
98
|
-
// Generate new key if pool is empty
|
|
99
|
-
key = this.generateKey();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Update mappings with new key information
|
|
103
|
-
this.keyMap.set(key, { itemType, stableId });
|
|
104
|
-
if (stableId) {
|
|
105
|
-
this.stableIdMap.set(stableId, key);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Ensure we don't exceed the maximum number of active keys
|
|
109
|
-
this.ensurePoolSize();
|
|
110
|
-
|
|
111
|
-
return key;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Recycles a key by adding it back to its item type's pool and cleaning up
|
|
116
|
-
* associated mappings. This should be called when a view is no longer visible.
|
|
117
|
-
* @param key - The key to be recycled
|
|
118
|
-
*/
|
|
119
|
-
public recycleKey(key: string): void {
|
|
120
|
-
const keyInfo = this.keyMap.get(key);
|
|
121
|
-
|
|
122
|
-
if (!keyInfo) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const { itemType, stableId } = keyInfo;
|
|
127
|
-
// Clean up stable ID mapping if it exists
|
|
128
|
-
if (stableId) {
|
|
129
|
-
this.stableIdMap.delete(stableId);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Add key back to its type's pool
|
|
133
|
-
let pool = this.keyPools.get(itemType);
|
|
134
|
-
if (!pool) {
|
|
135
|
-
pool = new Set();
|
|
136
|
-
this.keyPools.set(itemType, pool);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
pool.add(key);
|
|
140
|
-
this.keyMap.delete(key);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Checks if a key is currently available in the recycling pool.
|
|
145
|
-
* @param key - The key to check
|
|
146
|
-
* @returns True if the key is available in the pool, false otherwise
|
|
147
|
-
*/
|
|
148
|
-
public hasKeyInPool(key: string): boolean {
|
|
149
|
-
return !this.keyMap.has(key);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Clears all recycled keys from the pool, effectively resetting the recycling system.
|
|
154
|
-
* This operation does not affect currently active keys.
|
|
155
|
-
*/
|
|
156
|
-
public clearPool() {
|
|
157
|
-
this.keyPools.clear();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Generates a unique sequential key using an internal counter.
|
|
162
|
-
* @returns A unique key as a string
|
|
163
|
-
*/
|
|
164
|
-
private generateKey(): string {
|
|
165
|
-
return (this.keyCounter++).toString();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Ensures the total number of active keys doesn't exceed the maximum limit.
|
|
170
|
-
* If the limit is exceeded, recycles the oldest keys until within bounds.
|
|
171
|
-
* Note: This operation may impact performance when dealing with large lists.
|
|
172
|
-
* TODO: Check performance impact of this
|
|
173
|
-
*/
|
|
174
|
-
private ensurePoolSize(): void {
|
|
175
|
-
if (this.keyMap.size <= this.maxItems) return;
|
|
176
|
-
|
|
177
|
-
const keysToRecycle = Array.from(this.keyMap.keys()).slice(
|
|
178
|
-
0,
|
|
179
|
-
this.keyMap.size - this.maxItems
|
|
180
|
-
);
|
|
181
|
-
for (const key of keysToRecycle) {
|
|
182
|
-
this.recycleKey(key);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|