Skip to content

Commit a3da5b6

Browse files
committed
Remove initialValue param
1 parent 340f5f2 commit a3da5b6

6 files changed

Lines changed: 10 additions & 267 deletions

File tree

README.md

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,7 @@ export default withOnyx({
196196
})(App);
197197
```
198198

199-
Differently from `useOnyx()`, `withOnyx()` will delay the rendering of the wrapped component until all keys/entities have been fetched and passed to the component, this can be convenient for simple cases. This however, can really delay your application if many entities are connected to the same component, you can pass an `initialValue` to each key to allow Onyx to eagerly render your component with this value.
200-
201-
```javascript
202-
export default withOnyx({
203-
session: {
204-
key: ONYXKEYS.SESSION,
205-
initialValue: {}
206-
},
207-
})(App);
208-
```
199+
Differently from `useOnyx()`, `withOnyx()` will delay the rendering of the wrapped component until all keys/entities have been fetched and passed to the component, this can be convenient for simple cases. This however, can really delay your application if many entities are connected to the same component.
209200

210201
Additionally, if your component has many keys/entities when your component will mount but will receive many updates as data is fetched from DB and passed down to it, as every key that gets fetched will trigger a `setState` on the `withOnyx` HOC. This might cause re-renders on the initial mounting, preventing the component from mounting/rendering in reasonable time, making your app feel slow and even delaying animations.
211202

@@ -221,8 +212,7 @@ const App = ({session, markReadyForHydration}) => (
221212
// Second argument to funciton is `shouldDelayUpdates`
222213
export default withOnyx({
223214
session: {
224-
key: ONYXKEYS.SESSION,
225-
initialValue: {}
215+
key: ONYXKEYS.SESSION
226216
},
227217
}, true)(App);
228218
```

lib/useOnyx.ts

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ type BaseUseOnyxOptions = {
4848
canBeMissing?: boolean;
4949
};
5050

51-
type UseOnyxInitialValueOption<TInitialValue> = {
52-
/**
53-
* This value will be returned by the hook on the first render while the data is being read from Onyx.
54-
*/
55-
initialValue?: TInitialValue;
56-
};
57-
5851
type UseOnyxSelector<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>> = (data: OnyxValue<TKey> | undefined) => TReturnValue;
5952

6053
type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
@@ -68,7 +61,7 @@ type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
6861
selector?: UseOnyxSelector<TKey, TReturnValue>;
6962
};
7063

71-
type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & UseOnyxSelectorOption<TKey, TReturnValue>;
64+
type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = BaseUseOnyxOptions & UseOnyxSelectorOption<TKey, TReturnValue>;
7265

7366
type FetchStatus = 'loading' | 'loaded';
7467

@@ -81,14 +74,10 @@ type UseOnyxResult<TValue> = [NonNullable<TValue> | undefined, ResultMetadata<TV
8174

8275
function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
8376
key: TKey,
84-
options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & Required<UseOnyxSelectorOption<TKey, TReturnValue>>,
85-
dependencies?: DependencyList,
86-
): UseOnyxResult<TReturnValue>;
87-
function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
88-
key: TKey,
89-
options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<NoInfer<TReturnValue>>,
77+
options?: BaseUseOnyxOptions & Required<UseOnyxSelectorOption<TKey, TReturnValue>>,
9078
dependencies?: DependencyList,
9179
): UseOnyxResult<TReturnValue>;
80+
function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions, dependencies?: DependencyList): UseOnyxResult<TReturnValue>;
9281
function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
9382
key: TKey,
9483
options?: UseOnyxOptions<TKey, TReturnValue>,
@@ -226,13 +215,6 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
226215
newFetchStatus = 'loading';
227216
}
228217

229-
// If data is not present in cache and `initialValue` is set during the first connection,
230-
// we set the new value to `initialValue` and fetch status to `loaded` since we already have some data to return to the consumer.
231-
if (isFirstConnectionRef.current && !hasCacheForKey && options?.initialValue !== undefined) {
232-
newValueRef.current = options.initialValue;
233-
newFetchStatus = 'loaded';
234-
}
235-
236218
// We do a deep equality check if `selector` is defined, since each `tryGetCachedValue()` call will
237219
// generate a plain new primitive/object/array that was created using the `selector` function.
238220
// For the other cases we will only deal with object reference checks, so just a shallow equality check is enough.
@@ -272,7 +254,7 @@ function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(
272254
}
273255

274256
return resultRef.current;
275-
}, [options?.initWithStoredValues, options?.allowStaleData, options?.initialValue, options?.canBeMissing, key, selectorRef]);
257+
}, [options?.initWithStoredValues, options?.allowStaleData, options?.canBeMissing, key, selectorRef]);
276258

277259
const subscribe = useCallback(
278260
(onStoreChange: () => void) => {

lib/withOnyx/index.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import connectionManager from '../OnyxConnectionManager';
1515

1616
// This is a list of keys that can exist on a `mapping`, but are not directly related to loading data from Onyx. When the keys of a mapping are looped over to check
1717
// if a key has changed, it's a good idea to skip looking at these properties since they would have unexpected results.
18-
const mappingPropertiesToIgnoreChangesTo: Array<string | number | symbol> = ['initialValue', 'allowStaleData'];
18+
const mappingPropertiesToIgnoreChangesTo: Array<string | number | symbol> = ['allowStaleData'];
1919

2020
/**
2121
* Returns the display name of a component
@@ -85,13 +85,9 @@ export default function <TComponentProps, TOnyxProps>(
8585

8686
const cachedState = mapOnyxToStateEntries(mapOnyxToState).reduce<WithOnyxState<TOnyxProps>>((resultObj, [propName, mapping]) => {
8787
const key = Str.result(mapping.key as GenericFunction, props);
88-
let value = OnyxUtils.tryGetCachedValue(key, mapping as Mapping<OnyxKey>);
88+
const value = OnyxUtils.tryGetCachedValue(key, mapping as Mapping<OnyxKey>);
8989
const hasCacheForKey = cache.hasCacheForKey(key);
9090

91-
if (!hasCacheForKey && !value && mapping.initialValue) {
92-
value = mapping.initialValue;
93-
}
94-
9591
/**
9692
* If we have a pending merge for a key it could mean that data is being set via Onyx.merge() and someone expects a component to have this data immediately.
9793
*
@@ -247,15 +243,8 @@ export default function <TComponentProps, TOnyxProps>(
247243
return result;
248244
}
249245

250-
const initialValue = mapOnyxToState[key].initialValue;
251-
252-
// If initialValue is there and the state contains something different it means
253-
// an update has already been received and we can discard the value we are trying to hydrate
254-
if (initialValue !== undefined && prevState[key] !== undefined && prevState[key] !== initialValue && prevState[key] !== null) {
255-
// eslint-disable-next-line no-param-reassign
256-
result[key] = prevState[key];
257-
} else if (prevState[key] !== undefined && prevState[key] !== null) {
258-
// if value is already there (without initial value) then we can discard the value we are trying to hydrate
246+
// if value is already there then we can discard the value we are trying to hydrate
247+
if (prevState[key] !== undefined && prevState[key] !== null) {
259248
// eslint-disable-next-line no-param-reassign
260249
result[key] = prevState[key];
261250
} else if (stateUpdate[key] !== null) {

lib/withOnyx/types.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@ type BaseMapping<TComponentProps, TOnyxProps> = {
1111
allowStaleData?: boolean;
1212
};
1313

14-
/**
15-
* Represents the base mapping options when an Onyx collection key is supplied.
16-
*/
17-
type CollectionBaseMapping<TOnyxKey extends CollectionKeyBase> = {
18-
initialValue?: OnyxCollection<KeyValueMapping[TOnyxKey]>;
19-
};
20-
21-
/**
22-
* Represents the base mapping options when an Onyx non-collection key is supplied.
23-
*/
24-
type EntryBaseMapping<TOnyxKey extends OnyxKey> = {
25-
initialValue?: OnyxEntry<KeyValueMapping[TOnyxKey]>;
26-
};
27-
2814
/**
2915
* Represents the string / function `key` mapping option between an Onyx key and the component's prop.
3016
*
@@ -98,7 +84,6 @@ type BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TReturnType,
9884
* Represents the mapping options between an Onyx key and the component's prop with all its possibilities.
9985
*/
10086
type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey> = BaseMapping<TComponentProps, TOnyxProps> &
101-
EntryBaseMapping<TOnyxKey> &
10287
(
10388
| BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxEntry<KeyValueMapping[TOnyxKey]>>
10489
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey>
@@ -117,7 +102,6 @@ type WithOnyxMapping<TComponentProps, TOnyxProps> = Mapping<TComponentProps, TOn
117102
* Represents the mapping options between an Onyx collection key without suffix and the component's prop with all its possibilities.
118103
*/
119104
type CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends CollectionKeyBase> = BaseMapping<TComponentProps, TOnyxProps> &
120-
CollectionBaseMapping<TOnyxKey> &
121105
(
122106
| BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>>
123107
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey>

tests/unit/useOnyxTest.ts

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -386,82 +386,6 @@ describe('useOnyx', () => {
386386
expect(result.current[0]).toEqual('id - test_id, name - test_name - selector changed');
387387
expect(result.current[1].status).toEqual('loaded');
388388
});
389-
390-
it('should return initial value if selected data is undefined', async () => {
391-
const {result} = renderHook(() =>
392-
useOnyx(ONYXKEYS.TEST_KEY, {
393-
// @ts-expect-error bypass
394-
selector: (_entry: OnyxEntry<string>) => undefined,
395-
initialValue: 'initial value',
396-
}),
397-
);
398-
399-
expect(result.current[0]).toEqual('initial value');
400-
expect(result.current[1].status).toEqual('loaded');
401-
402-
Onyx.set(ONYXKEYS.TEST_KEY, 'test_id_1');
403-
404-
await act(async () => waitForPromisesToResolve());
405-
406-
expect(result.current[0]).toBeUndefined();
407-
expect(result.current[1].status).toEqual('loaded');
408-
});
409-
});
410-
411-
describe('initialValue', () => {
412-
it('should return initial value from non-cached key and then return undefined', async () => {
413-
const {result} = renderHook(() =>
414-
useOnyx(ONYXKEYS.TEST_KEY, {
415-
initialValue: 'initial value',
416-
}),
417-
);
418-
419-
expect(result.current[0]).toEqual('initial value');
420-
expect(result.current[1].status).toEqual('loaded');
421-
422-
await act(async () => waitForPromisesToResolve());
423-
424-
expect(result.current[0]).toBeUndefined();
425-
expect(result.current[1].status).toEqual('loaded');
426-
});
427-
428-
it('should return initial value from cached key and then return cached value', async () => {
429-
await StorageMock.setItem(ONYXKEYS.TEST_KEY, 'test');
430-
431-
const {result} = renderHook(() =>
432-
useOnyx(ONYXKEYS.TEST_KEY, {
433-
initialValue: 'initial value',
434-
}),
435-
);
436-
437-
expect(result.current[0]).toEqual('initial value');
438-
expect(result.current[1].status).toEqual('loaded');
439-
440-
await act(async () => waitForPromisesToResolve());
441-
442-
expect(result.current[0]).toEqual('test');
443-
expect(result.current[1].status).toEqual('loaded');
444-
});
445-
446-
it('should return initial value from cached key and then return selected data', async () => {
447-
await StorageMock.setItem(ONYXKEYS.TEST_KEY, 'test');
448-
449-
const {result} = renderHook(() =>
450-
useOnyx(ONYXKEYS.TEST_KEY, {
451-
initialValue: 'initial value',
452-
// @ts-expect-error bypass
453-
selector: (entry: OnyxEntry<string>) => `${entry}_changed`,
454-
}),
455-
);
456-
457-
expect(result.current[0]).toEqual('initial value');
458-
expect(result.current[1].status).toEqual('loaded');
459-
460-
await act(async () => waitForPromisesToResolve());
461-
462-
expect(result.current[0]).toEqual('test_changed');
463-
expect(result.current[1].status).toEqual('loaded');
464-
});
465389
});
466390

467391
describe('allowStaleData', () => {
@@ -506,28 +430,6 @@ describe('useOnyx', () => {
506430
expect(result.current[1].status).toEqual('loaded');
507431
});
508432

509-
it('should return initial value and loaded state while we have pending merges for the key, and then return updated value and loaded state', async () => {
510-
const {result} = renderHook(() =>
511-
useOnyx(ONYXKEYS.TEST_KEY, {
512-
initialValue: 'initial value',
513-
}),
514-
);
515-
516-
expect(result.current[0]).toEqual('initial value');
517-
expect(result.current[1].status).toEqual('loaded');
518-
519-
Onyx.set(ONYXKEYS.TEST_KEY, 'test1');
520-
521-
Onyx.merge(ONYXKEYS.TEST_KEY, 'test2');
522-
Onyx.merge(ONYXKEYS.TEST_KEY, 'test3');
523-
Onyx.merge(ONYXKEYS.TEST_KEY, 'test4');
524-
525-
await act(async () => waitForPromisesToResolve());
526-
527-
expect(result.current[0]).toEqual('test4');
528-
expect(result.current[1].status).toEqual('loaded');
529-
});
530-
531433
it('should return stale value and loaded state if allowStaleData is true, and then return updated value and loaded state', async () => {
532434
Onyx.set(ONYXKEYS.TEST_KEY, 'test1');
533435

@@ -564,27 +466,6 @@ describe('useOnyx', () => {
564466
expect(result.current[1].status).toEqual('loaded');
565467
});
566468

567-
it('should return `undefined` and loaded state if using `initialValue`, and after merge return updated value and loaded state', async () => {
568-
await StorageMock.setItem(ONYXKEYS.TEST_KEY, 'test1');
569-
570-
const {result} = renderHook(() =>
571-
useOnyx(ONYXKEYS.TEST_KEY, {
572-
initWithStoredValues: false,
573-
initialValue: 'initial value',
574-
}),
575-
);
576-
577-
await act(async () => waitForPromisesToResolve());
578-
579-
expect(result.current[0]).toBeUndefined();
580-
expect(result.current[1].status).toEqual('loaded');
581-
582-
await act(async () => Onyx.merge(ONYXKEYS.TEST_KEY, 'test'));
583-
584-
expect(result.current[0]).toEqual('test');
585-
expect(result.current[1].status).toEqual('loaded');
586-
});
587-
588469
it('should return `undefined` value and loaded state if using `selector`, and after merge return selected value and loaded state', async () => {
589470
await StorageMock.setItem(ONYXKEYS.TEST_KEY, 'test1');
590471

tests/unit/withOnyxTest.tsx

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -574,89 +574,6 @@ describe('withOnyxTest', () => {
574574
);
575575
});
576576

577-
it('initialValue should be fed into component', () => {
578-
const onRender = jest.fn();
579-
const markReadyForHydration = jest.fn();
580-
581-
return waitForPromisesToResolve()
582-
.then(() => {
583-
// When a component subscribes to the simple key
584-
const TestComponentWithOnyx = withOnyx<ViewWithCollectionsProps, {simple: unknown}>({
585-
simple: {
586-
key: ONYX_KEYS.SIMPLE_KEY,
587-
initialValue: 'initialValue',
588-
},
589-
})(ViewWithCollections);
590-
render(
591-
<TestComponentWithOnyx
592-
markReadyForHydration={markReadyForHydration}
593-
onRender={onRender}
594-
/>,
595-
);
596-
})
597-
.then(() => {
598-
// Then the component subscribed to the modified item should only render once
599-
expect(onRender).toHaveBeenCalledTimes(1);
600-
expect(onRender).toHaveBeenLastCalledWith({
601-
collections: {},
602-
markReadyForHydration,
603-
onRender,
604-
testObject: {isDefaultProp: true},
605-
simple: 'initialValue',
606-
});
607-
});
608-
});
609-
610-
it('shouldDelayUpdates + initialValue does not feed data into component until marked ready', () => {
611-
const onRender = jest.fn();
612-
const ref = React.createRef<{markReadyForHydration: () => void}>();
613-
614-
return (
615-
waitForPromisesToResolve()
616-
.then(() => {
617-
// When a component subscribes to the simple key
618-
const TestComponentWithOnyx = withOnyx<ViewWithCollectionsProps, {simple: unknown}>(
619-
{
620-
simple: {
621-
key: ONYX_KEYS.SIMPLE_KEY,
622-
initialValue: 'initialValue',
623-
},
624-
},
625-
true,
626-
)(ViewWithCollections);
627-
628-
render(
629-
<TestComponentWithOnyx
630-
onRender={onRender}
631-
ref={ref}
632-
/>,
633-
);
634-
})
635-
636-
// component mounted with the initial value, while updates are queueing
637-
.then(() => Onyx.merge(ONYX_KEYS.SIMPLE_KEY, 'string'))
638-
.then(() => {
639-
expect(onRender).toHaveBeenCalledTimes(1);
640-
expect(onRender.mock.calls[0][0].simple).toBe('initialValue');
641-
642-
// just to test we change the value
643-
return Onyx.merge(ONYX_KEYS.SIMPLE_KEY, 'long_string');
644-
})
645-
.then(() => {
646-
// Component still has not updated
647-
expect(onRender).toHaveBeenCalledTimes(1);
648-
649-
// We can now tell component to update
650-
ref.current?.markReadyForHydration();
651-
})
652-
.then(() => {
653-
// Now that the component has been marked as ready for hydration, it has been updated
654-
expect(onRender).toHaveBeenCalledTimes(4);
655-
expect(onRender.mock.calls[3][0].simple).toBe('long_string');
656-
})
657-
);
658-
});
659-
660577
it('should render immediately when a onyx component is mounted a 2nd time', () => {
661578
const TestComponentWithOnyx = withOnyx<ViewWithTextProps, ViewWithTextOnyxProps>({
662579
text: {

0 commit comments

Comments
 (0)