Skip to content

Commit 6b717dd

Browse files
committed
reset internal useOnyx state on key change
1 parent 29b7061 commit 6b717dd

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

lib/useOnyx.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
135135
// Inside useOnyx.ts, we need to track the sourceValue separately
136136
const sourceValueRef = useRef<NonNullable<TReturnValue> | undefined>(undefined);
137137

138+
// When the key changes, reset internal state so the hook properly transitions through loading
139+
// for the new key instead of preserving stale status from the previous key.
140+
if (key !== previousKey) {
141+
previousValueRef.current = null;
142+
newValueRef.current = null;
143+
isFirstConnectionRef.current = true;
144+
shouldGetCachedValueRef.current = true;
145+
sourceValueRef.current = undefined;
146+
resultRef.current = [undefined, {status: options?.initWithStoredValues === false ? 'loaded' : 'loading'}];
147+
}
148+
138149
// Cache the options key to avoid regenerating it every getSnapshot call
139150
const cacheKey = useMemo(
140151
() =>

tests/unit/useOnyxTest.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,89 @@ describe('useOnyx', () => {
138138
fail("Expected to don't throw any errors.");
139139
}
140140
});
141+
142+
it('should transition through loading when switching between collection member keys that both resolve to undefined', async () => {
143+
const {result, rerender} = renderHook((key: string) => useOnyx(key), {initialProps: `${ONYXKEYS.COLLECTION.TEST_KEY}1` as string});
144+
145+
// Wait for initial key to fully load
146+
await act(async () => waitForPromisesToResolve());
147+
148+
expect(result.current[0]).toBeUndefined();
149+
expect(result.current[1].status).toEqual('loaded');
150+
151+
// Switch to another collection member key that also has no data
152+
rerender(`${ONYXKEYS.COLLECTION.TEST_KEY}2`);
153+
154+
expect(result.current[0]).toBeUndefined();
155+
expect(result.current[1].status).toEqual('loading');
156+
157+
await act(async () => waitForPromisesToResolve());
158+
159+
expect(result.current[0]).toBeUndefined();
160+
expect(result.current[1].status).toEqual('loaded');
161+
});
162+
163+
it('should return cached value immediately with loaded status when switching to a key that has data', async () => {
164+
Onyx.set(`${ONYXKEYS.COLLECTION.TEST_KEY}2`, 'test_value');
165+
166+
const {result, rerender} = renderHook((key: string) => useOnyx(key), {initialProps: `${ONYXKEYS.COLLECTION.TEST_KEY}1` as string});
167+
168+
await act(async () => waitForPromisesToResolve());
169+
170+
expect(result.current[0]).toBeUndefined();
171+
expect(result.current[1].status).toEqual('loaded');
172+
173+
// Switch to a key that has cached data
174+
rerender(`${ONYXKEYS.COLLECTION.TEST_KEY}2`);
175+
176+
await act(async () => waitForPromisesToResolve());
177+
178+
expect(result.current[0]).toEqual('test_value');
179+
expect(result.current[1].status).toEqual('loaded');
180+
});
181+
182+
it('should clear previous data and transition through loading when switching from a key with data to one without', async () => {
183+
Onyx.set(`${ONYXKEYS.COLLECTION.TEST_KEY}1`, 'initial_value');
184+
185+
const {result, rerender} = renderHook((key: string) => useOnyx(key), {initialProps: `${ONYXKEYS.COLLECTION.TEST_KEY}1` as string});
186+
187+
await act(async () => waitForPromisesToResolve());
188+
189+
expect(result.current[0]).toEqual('initial_value');
190+
expect(result.current[1].status).toEqual('loaded');
191+
192+
// Switch to a key that has no data
193+
rerender(`${ONYXKEYS.COLLECTION.TEST_KEY}2`);
194+
195+
expect(result.current[0]).toBeUndefined();
196+
expect(result.current[1].status).toEqual('loading');
197+
198+
await act(async () => waitForPromisesToResolve());
199+
200+
expect(result.current[0]).toBeUndefined();
201+
expect(result.current[1].status).toEqual('loaded');
202+
});
203+
204+
it('should transition through loading when switching between collection member keys using allowDynamicKey', async () => {
205+
const {result, rerender} = renderHook((key: string) => useOnyx(key, {allowDynamicKey: true}), {
206+
initialProps: `${ONYXKEYS.COLLECTION.TEST_KEY}1` as string,
207+
});
208+
209+
await act(async () => waitForPromisesToResolve());
210+
211+
expect(result.current[0]).toBeUndefined();
212+
expect(result.current[1].status).toEqual('loaded');
213+
214+
rerender(`${ONYXKEYS.COLLECTION.TEST_KEY}2`);
215+
216+
expect(result.current[0]).toBeUndefined();
217+
expect(result.current[1].status).toEqual('loading');
218+
219+
await act(async () => waitForPromisesToResolve());
220+
221+
expect(result.current[0]).toBeUndefined();
222+
expect(result.current[1].status).toEqual('loaded');
223+
});
141224
});
142225

143226
describe('misc', () => {

0 commit comments

Comments
 (0)