Skip to content

Commit ec0ba98

Browse files
committed
apply alternative solution, remove original one
1 parent 8450987 commit ec0ba98

1 file changed

Lines changed: 25 additions & 24 deletions

File tree

lib/useOnyx.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,12 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
114114
},
115115
]);
116116

117-
// Indicates if it's the first Onyx connection of this hook or not, as we don't want certain use cases
118-
// in `getSnapshot()` to be satisfied several times.
119-
const isFirstConnectionRef = useRef(true);
117+
// Tracks which key has completed its first Onyx connection callback. When this doesn't match the
118+
// current key, getSnapshot() treats the hook as being in its "first connection" state for that key.
119+
// This is key-aware by design: when the key changes, connectedKeyRef still holds the old key (or null
120+
// after cleanup), so the hook automatically enters first-connection mode for the new key without any
121+
// explicit reset logic — eliminating the race condition where cleanup could clobber a boolean flag.
122+
const connectedKeyRef = useRef<OnyxKey | null>(null);
120123

121124
// Indicates if the hook is connecting to an Onyx key.
122125
const isConnectingRef = useRef(false);
@@ -130,17 +133,6 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
130133
// Inside useOnyx.ts, we need to track the sourceValue separately
131134
const sourceValueRef = useRef<NonNullable<TReturnValue> | undefined>(undefined);
132135

133-
// When the key changes, reset internal state so the hook properly transitions through loading
134-
// for the new key instead of preserving stale status from the previous key.
135-
if (key !== previousKey) {
136-
previousValueRef.current = null;
137-
newValueRef.current = null;
138-
isFirstConnectionRef.current = true;
139-
shouldGetCachedValueRef.current = true;
140-
sourceValueRef.current = undefined;
141-
resultRef.current = [undefined, {status: options?.initWithStoredValues === false ? 'loaded' : 'loading'}];
142-
}
143-
144136
// Cache the options key to avoid regenerating it every getSnapshot call
145137
const cacheKey = useMemo(
146138
() =>
@@ -169,7 +161,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
169161

170162
previousDependenciesRef.current = dependencies;
171163

172-
if (connectionRef.current === null || isConnectingRef.current || !onStoreChangeFnRef.current) {
164+
if (connectionRef.current === null || isConnectingRef.current || connectedKeyRef.current !== key || !onStoreChangeFnRef.current) {
173165
return;
174166
}
175167

@@ -205,7 +197,8 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
205197
// Check if we have any cache for this Onyx key
206198
// Don't use cache for first connection with initWithStoredValues: false
207199
// Also don't use cache during active data updates (when shouldGetCachedValueRef is true)
208-
if (!(isFirstConnectionRef.current && options?.initWithStoredValues === false) && !shouldGetCachedValueRef.current) {
200+
const isFirstConnection = connectedKeyRef.current !== key;
201+
if (!(isFirstConnection && options?.initWithStoredValues === false) && !shouldGetCachedValueRef.current) {
209202
const cachedResult = onyxSnapshotCache.getCachedResult<UseOnyxResult<TReturnValue>>(key, cacheKey);
210203
if (cachedResult !== undefined) {
211204
resultRef.current = cachedResult;
@@ -214,7 +207,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
214207
}
215208

216209
// We return the initial result right away during the first connection if `initWithStoredValues` is set to `false`.
217-
if (isFirstConnectionRef.current && options?.initWithStoredValues === false) {
210+
if (isFirstConnection && options?.initWithStoredValues === false) {
218211
const result = resultRef.current;
219212

220213
// Store result in snapshot cache
@@ -226,7 +219,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
226219
// so we can return any cached value right away. For the case where the key has changed, If we don't return the cached value right away, then the UI will show the incorrect (previous) value for a brief period which looks like a UI glitch to the user. After the connection is made, we only
227220
// update `newValueRef` when `Onyx.connect()` callback is fired.
228221
const hasSelectorChanged = lastComputedSelectorRef.current !== memoizedSelector;
229-
if (isFirstConnectionRef.current || shouldGetCachedValueRef.current || key !== previousKey || hasSelectorChanged) {
222+
if (isFirstConnection || shouldGetCachedValueRef.current || key !== previousKey || hasSelectorChanged) {
230223
// Gets the value from cache and maps it with selector. It changes `null` to `undefined` for `useOnyx` compatibility.
231224
const value = OnyxUtils.tryGetCachedValue(key) as OnyxValue<TKey>;
232225
const selectedValue = memoizedSelector ? memoizedSelector(value) : value;
@@ -245,7 +238,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
245238

246239
// If we have pending merge operations for the key during the first connection, we set the new value to `undefined`
247240
// and fetch status to `loading` to simulate that it is still being loaded until we have the most updated data.
248-
if (isFirstConnectionRef.current && OnyxUtils.hasPendingMergeForKey(key)) {
241+
if (isFirstConnection && OnyxUtils.hasPendingMergeForKey(key)) {
249242
newValueRef.current = undefined;
250243
newFetchStatus = 'loading';
251244
}
@@ -270,7 +263,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
270263
// OR we have a pending `Onyx.clear()` task (if `Onyx.clear()` is running cache might not be available anymore
271264
// OR the subscriber is triggered (the value is gotten from the storage)
272265
// so we update the cached value/result right away in order to prevent infinite loading state issues).
273-
const shouldUpdateResult = !areValuesEqual || (previousValueRef.current === null && (hasCacheForKey || OnyxCache.hasPendingTask(TASK.CLEAR) || !isFirstConnectionRef.current));
266+
const shouldUpdateResult = !areValuesEqual || (previousValueRef.current === null && (hasCacheForKey || OnyxCache.hasPendingTask(TASK.CLEAR) || !isFirstConnection));
274267
if (shouldUpdateResult) {
275268
previousValueRef.current = newValueRef.current;
276269

@@ -294,6 +287,14 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
294287

295288
const subscribe = useCallback(
296289
(onStoreChange: () => void) => {
290+
// Reset internal state so the hook properly transitions through loading
291+
// for the new key instead of preserving stale state from the previous one.
292+
previousValueRef.current = null;
293+
newValueRef.current = null;
294+
shouldGetCachedValueRef.current = true;
295+
sourceValueRef.current = undefined;
296+
resultRef.current = [undefined, {status: options?.initWithStoredValues === false ? 'loaded' : 'loading'}];
297+
297298
isConnectingRef.current = true;
298299
onStoreChangeFnRef.current = onStoreChange;
299300

@@ -303,9 +304,9 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
303304
isConnectingRef.current = false;
304305
onStoreChangeFnRef.current = onStoreChange;
305306

306-
// Signals that the first connection was made, so some logics in `getSnapshot()`
307-
// won't be executed anymore.
308-
isFirstConnectionRef.current = false;
307+
// Signals that the first connection was made for this key, so some logics
308+
// in `getSnapshot()` won't be executed anymore.
309+
connectedKeyRef.current = key;
309310

310311
// Signals that we want to get the newest cached value again in `getSnapshot()`.
311312
shouldGetCachedValueRef.current = true;
@@ -332,7 +333,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
332333
}
333334

334335
connectionManager.disconnect(connectionRef.current);
335-
isFirstConnectionRef.current = false;
336+
connectedKeyRef.current = null;
336337
isConnectingRef.current = false;
337338
onStoreChangeFnRef.current = null;
338339
};

0 commit comments

Comments
 (0)