Skip to content

Commit e77a803

Browse files
committed
Minor fixes
1 parent ea305ab commit e77a803

2 files changed

Lines changed: 19 additions & 36 deletions

File tree

lib/OnyxCache.ts

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,18 @@ import {deepEqual} from 'fast-equals';
22
import bindAll from 'lodash/bindAll';
33
import type {ValueOf} from 'type-fest';
44
import utils from './utils';
5-
import type {KeyValueMapping, NonUndefined, OnyxCollection, OnyxKey, OnyxValue} from './types';
5+
import type {CollectionKeyBase, KeyValueMapping, NonUndefined, OnyxCollection, OnyxKey, OnyxValue} from './types';
66
import OnyxKeys from './OnyxKeys';
77

8-
type CollectionSnapshot = {
9-
/** Monotonically increasing version number, bumped on any member change */
10-
version: number;
11-
/** Frozen object containing all collection members — safe to return by reference */
12-
snapshot: Readonly<NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>>>;
13-
};
8+
/** Frozen object containing all collection members — safe to return by reference */
9+
type CollectionSnapshot = Readonly<NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>>>;
1410

1511
/**
1612
* Stable frozen empty object used as the canonical value for empty collections.
1713
* Returning the same reference avoids unnecessary re-renders in useSyncExternalStore,
1814
* which relies on === equality to detect changes.
1915
*/
20-
const FROZEN_EMPTY_COLLECTION: Readonly<Record<OnyxKey, OnyxValue<OnyxKey>>> = Object.freeze({});
16+
const FROZEN_EMPTY_COLLECTION: Readonly<NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>>> = Object.freeze({});
2117

2218
// Task constants
2319
const TASK = {
@@ -63,11 +59,11 @@ class OnyxCache {
6359
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
6460
private recentlyAccessedKeys = new Set<OnyxKey>();
6561

66-
/** Versioned frozen collection snapshots for structural sharing */
62+
/** Frozen collection snapshots for structural sharing */
6763
private collectionSnapshots: Map<OnyxKey, CollectionSnapshot>;
6864

6965
/** Collections whose snapshots need rebuilding (lazy — rebuilt on next read) */
70-
private dirtyCollections: Set<OnyxKey>;
66+
private dirtyCollections: Set<CollectionKeyBase>;
7167

7268
constructor() {
7369
this.storageKeys = new Set();
@@ -108,7 +104,6 @@ class OnyxCache {
108104
'setCollectionKeys',
109105
'hasValueChanged',
110106
'getCollectionData',
111-
'getCollectionVersion',
112107
);
113108
}
114109

@@ -476,10 +471,7 @@ class OnyxCache {
476471
// Initialize frozen snapshots for collection keys
477472
for (const collectionKey of collectionKeys) {
478473
if (!this.collectionSnapshots.has(collectionKey)) {
479-
this.collectionSnapshots.set(collectionKey, {
480-
version: 0,
481-
snapshot: Object.freeze({}),
482-
});
474+
this.collectionSnapshots.set(collectionKey, Object.freeze({}));
483475
}
484476
}
485477

@@ -498,8 +490,7 @@ class OnyxCache {
498490
* @param collectionKey - The collection key to rebuild
499491
*/
500492
private rebuildCollectionSnapshot(collectionKey: OnyxKey): void {
501-
const existing = this.collectionSnapshots.get(collectionKey);
502-
const oldSnapshot = existing?.snapshot;
493+
const oldSnapshot = this.collectionSnapshots.get(collectionKey);
503494

504495
const members: NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>> = {};
505496
let hasChanges = false;
@@ -539,16 +530,12 @@ class OnyxCache {
539530
// This is critical: useSyncExternalStore uses === to detect changes,
540531
// so returning the same reference prevents unnecessary re-renders.
541532
if (!hasChanges && oldSnapshot) {
542-
// Don't even bump the version — nothing changed
543533
return;
544534
}
545535

546536
Object.freeze(members);
547537

548-
this.collectionSnapshots.set(collectionKey, {
549-
version: (existing?.version ?? 0) + 1,
550-
snapshot: members,
551-
});
538+
this.collectionSnapshots.set(collectionKey, members);
552539
}
553540

554541
/**
@@ -562,8 +549,8 @@ class OnyxCache {
562549
this.dirtyCollections.delete(collectionKey);
563550
}
564551

565-
const entry = this.collectionSnapshots.get(collectionKey);
566-
if (!entry || Object.keys(entry.snapshot).length === 0) {
552+
const snapshot = this.collectionSnapshots.get(collectionKey);
553+
if (!snapshot || Object.keys(snapshot).length === 0) {
567554
// If we know we have storage keys loaded, return a stable empty reference
568555
// to avoid new {} allocations that break useSyncExternalStore === equality.
569556
if (this.storageKeys.size > 0) {
@@ -572,15 +559,7 @@ class OnyxCache {
572559
return undefined;
573560
}
574561

575-
return entry.snapshot;
576-
}
577-
578-
/**
579-
* Get the version number for a collection's snapshot.
580-
* Useful for cheap O(1) change detection.
581-
*/
582-
getCollectionVersion(collectionKey: OnyxKey): number {
583-
return this.collectionSnapshots.get(collectionKey)?.version ?? 0;
562+
return snapshot;
584563
}
585564
}
586565

lib/OnyxUtils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type {
3030
SetParams,
3131
OnyxMultiSetInput,
3232
RetriableOnyxOperation,
33+
NonUndefined,
3334
} from './types';
3435
import type {FastMergeOptions, FastMergeResult} from './utils';
3536
import utils from './utils';
@@ -1279,8 +1280,11 @@ function multiSetWithRetry(data: OnyxMultiSetInput, retryAttempt?: number): Prom
12791280
// Group keys by collection for batched notification, and track non-collection keys separately.
12801281
// This avoids firing N individual keyChanged() calls for N collection members — instead we
12811282
// update all members in cache first, then notify collection subscribers once per collection.
1282-
const collectionBatches = new Map<string, {partial: Record<string, OnyxValue<OnyxKey>>; previous: Record<string, OnyxValue<OnyxKey>>}>();
1283-
const nonCollectionPairs: Array<[string, OnyxValue<OnyxKey>]> = [];
1283+
const collectionBatches = new Map<
1284+
CollectionKeyBase,
1285+
{partial: NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>>; previous: NonUndefined<OnyxCollection<KeyValueMapping[OnyxKey]>>}
1286+
>();
1287+
const nonCollectionPairs: Array<[OnyxKey, OnyxValue<OnyxKey>]> = [];
12841288

12851289
for (const [key, value] of keyValuePairsToSet) {
12861290
// Clear any pending merge deltas for this key
@@ -1309,7 +1313,7 @@ function multiSetWithRetry(data: OnyxMultiSetInput, retryAttempt?: number): Prom
13091313

13101314
// Notify collection subscribers once per collection (batched)
13111315
for (const [collectionKey, batch] of collectionBatches) {
1312-
keysChanged(collectionKey as CollectionKeyBase, batch.partial, batch.previous);
1316+
keysChanged(collectionKey, batch.partial, batch.previous);
13131317
}
13141318

13151319
// Notify non-collection key subscribers individually

0 commit comments

Comments
 (0)