react-native-onyx 2.0.40 → 2.0.42
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/dist/OnyxUtils.d.ts +1 -1
- package/dist/OnyxUtils.js +3 -3
- package/dist/index.d.ts +6 -5
- package/dist/index.js +1 -1
- package/dist/types.d.ts +4 -13
- package/dist/useOnyx.d.ts +2 -2
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +50 -1
- package/dist/withOnyx/index.d.ts +15 -0
- package/dist/{withOnyx.js → withOnyx/index.js} +50 -58
- package/dist/{withOnyx.d.ts → withOnyx/types.d.ts} +45 -45
- package/dist/withOnyx/types.js +2 -0
- package/package.json +2 -2
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ValueOf } from 'type-fest';
|
|
2
|
-
import type { DeepRecord, Mapping, CollectionKey, CollectionKeyBase, NullableKeyValueMapping, OnyxKey, OnyxValue, OnyxCollection, WithOnyxConnectOptions, OnyxEntry, KeyValueMapping } from './types';
|
|
3
2
|
import type Onyx from './Onyx';
|
|
3
|
+
import type { CollectionKey, CollectionKeyBase, DeepRecord, KeyValueMapping, Mapping, NullableKeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, WithOnyxConnectOptions } from './types';
|
|
4
4
|
declare const METHOD: {
|
|
5
5
|
readonly SET: "set";
|
|
6
6
|
readonly MERGE: "merge";
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -30,14 +30,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
30
30
|
/* eslint-disable no-continue */
|
|
31
31
|
const fast_equals_1 = require("fast-equals");
|
|
32
32
|
const clone_1 = __importDefault(require("lodash/clone"));
|
|
33
|
+
const DevTools_1 = __importDefault(require("./DevTools"));
|
|
33
34
|
const Logger = __importStar(require("./Logger"));
|
|
34
35
|
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
|
|
35
|
-
const Str = __importStar(require("./Str"));
|
|
36
36
|
const PerformanceUtils = __importStar(require("./PerformanceUtils"));
|
|
37
|
+
const Str = __importStar(require("./Str"));
|
|
38
|
+
const batch_1 = __importDefault(require("./batch"));
|
|
37
39
|
const storage_1 = __importDefault(require("./storage"));
|
|
38
40
|
const utils_1 = __importDefault(require("./utils"));
|
|
39
|
-
const batch_1 = __importDefault(require("./batch"));
|
|
40
|
-
const DevTools_1 = __importDefault(require("./DevTools"));
|
|
41
41
|
// Method constants
|
|
42
42
|
const METHOD = {
|
|
43
43
|
SET: 'set',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { ConnectOptions, OnyxUpdate } from './Onyx';
|
|
1
2
|
import Onyx from './Onyx';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { UseOnyxResult, FetchStatus, ResultMetadata } from './useOnyx';
|
|
3
|
+
import type { CustomTypeOptions, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector } from './types';
|
|
4
|
+
import type { FetchStatus, ResultMetadata, UseOnyxResult } from './useOnyx';
|
|
5
5
|
import useOnyx from './useOnyx';
|
|
6
6
|
import withOnyx from './withOnyx';
|
|
7
|
+
import type { WithOnyxState } from './withOnyx/types';
|
|
7
8
|
export default Onyx;
|
|
8
|
-
export {
|
|
9
|
-
export type {
|
|
9
|
+
export { useOnyx, withOnyx };
|
|
10
|
+
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.withOnyx = exports.useOnyx = void 0;
|
|
7
7
|
const Onyx_1 = __importDefault(require("./Onyx"));
|
|
8
8
|
const useOnyx_1 = __importDefault(require("./useOnyx"));
|
|
9
9
|
exports.useOnyx = useOnyx_1.default;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Component } from 'react';
|
|
2
1
|
import type { Merge } from 'type-fest';
|
|
3
2
|
import type { BuiltIns } from 'type-fest/source/internal';
|
|
4
3
|
import type OnyxUtils from './OnyxUtils';
|
|
4
|
+
import type { WithOnyxInstance, WithOnyxState } from './withOnyx/types';
|
|
5
5
|
/**
|
|
6
6
|
* Utility type that excludes `null` from the type `TValue`.
|
|
7
7
|
*/
|
|
@@ -132,7 +132,7 @@ type NullableKeyValueMapping = {
|
|
|
132
132
|
* The type `TKey` extends `OnyxKey` and it is the key used to access a value in `KeyValueMapping`.
|
|
133
133
|
* `TReturnType` is the type of the returned value from the selector function.
|
|
134
134
|
*/
|
|
135
|
-
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state
|
|
135
|
+
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state?: WithOnyxState<TOnyxProps>) => TReturnType;
|
|
136
136
|
/**
|
|
137
137
|
* Represents a single Onyx entry, that can be either `TOnyxValue` or `null` / `undefined` if it doesn't exist.
|
|
138
138
|
*
|
|
@@ -220,12 +220,6 @@ type NullishDeep<T> = T extends NonTransformableTypes ? T : T extends object ? N
|
|
|
220
220
|
type NullishObjectDeep<ObjectType extends object> = {
|
|
221
221
|
[KeyType in keyof ObjectType]?: NullishDeep<ObjectType[KeyType]> | null;
|
|
222
222
|
};
|
|
223
|
-
/**
|
|
224
|
-
* Represents withOnyx's internal state, containing the Onyx props and a `loading` flag.
|
|
225
|
-
*/
|
|
226
|
-
type WithOnyxInstanceState<TOnyxProps> = (TOnyxProps & {
|
|
227
|
-
loading: boolean;
|
|
228
|
-
}) | undefined;
|
|
229
223
|
/**
|
|
230
224
|
* Represents a mapping between Onyx collection keys and their respective values.
|
|
231
225
|
*
|
|
@@ -238,10 +232,6 @@ type WithOnyxInstanceState<TOnyxProps> = (TOnyxProps & {
|
|
|
238
232
|
type Collection<TKey extends CollectionKeyBase, TMap, TValue> = {
|
|
239
233
|
[MapK in keyof TMap]: MapK extends `${TKey}${string}` ? MapK extends `${TKey}` ? never : TValue : never;
|
|
240
234
|
};
|
|
241
|
-
type WithOnyxInstance = Component<unknown, WithOnyxInstanceState<NullableKeyValueMapping>> & {
|
|
242
|
-
setStateProxy: (cb: (state: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>>) => OnyxValue<OnyxKey>) => void;
|
|
243
|
-
setWithOnyxState: (statePropertyName: OnyxKey, value: OnyxValue<OnyxKey>) => void;
|
|
244
|
-
};
|
|
245
235
|
/** Represents the base options used in `Onyx.connect()` method. */
|
|
246
236
|
type BaseConnectOptions = {
|
|
247
237
|
initWithStoredValues?: boolean;
|
|
@@ -342,4 +332,5 @@ type InitOptions = {
|
|
|
342
332
|
/** Enables debugging setState() calls to connected components */
|
|
343
333
|
debugSetState?: boolean;
|
|
344
334
|
};
|
|
345
|
-
|
|
335
|
+
type GenericFunction = (...args: any[]) => any;
|
|
336
|
+
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, };
|
package/dist/useOnyx.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { CollectionKeyBase, KeyValueMapping, NonNull, OnyxCollection, OnyxE
|
|
|
4
4
|
* Represents a Onyx value that can be either a single entry or a collection of entries, depending on the `TKey` provided.
|
|
5
5
|
* It's a variation of `OnyxValue` type that is read-only and excludes the `null` type.
|
|
6
6
|
*/
|
|
7
|
-
type UseOnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey extends CollectionKeyBase ?
|
|
7
|
+
type UseOnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey extends CollectionKeyBase ? NonNull<OnyxCollection<KeyValueMapping[TKey]>> : NonNull<OnyxEntry<KeyValueMapping[TKey]>>;
|
|
8
8
|
type BaseUseOnyxOptions = {
|
|
9
9
|
/**
|
|
10
10
|
* Determines if this key in this subscription is safe to be evicted.
|
|
@@ -35,7 +35,7 @@ type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
|
|
|
35
35
|
selector?: Selector<TKey, unknown, TReturnValue>;
|
|
36
36
|
};
|
|
37
37
|
type FetchStatus = 'loading' | 'loaded';
|
|
38
|
-
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, UseOnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ?
|
|
38
|
+
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, UseOnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ? NonNullable<OnyxCollection<TValue>> : TValue;
|
|
39
39
|
type ResultMetadata = {
|
|
40
40
|
status: FetchStatus;
|
|
41
41
|
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -21,11 +21,29 @@ declare function checkCompatibilityWithExistingValue(value: unknown, existingVal
|
|
|
21
21
|
existingValueType?: string;
|
|
22
22
|
newValueType?: string;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Picks entries from an object based on a condition.
|
|
26
|
+
*
|
|
27
|
+
* @param obj - The object to pick entries from.
|
|
28
|
+
* @param condition - The condition to determine which entries to pick.
|
|
29
|
+
* @returns The object containing only the picked entries.
|
|
30
|
+
*/
|
|
31
|
+
declare function pick<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean)): Record<string, TValue>;
|
|
32
|
+
/**
|
|
33
|
+
* Omits entries from an object based on a condition.
|
|
34
|
+
*
|
|
35
|
+
* @param obj - The object to omit entries from.
|
|
36
|
+
* @param condition - The condition to determine which entries to omit.
|
|
37
|
+
* @returns The object containing only the remaining entries after omission.
|
|
38
|
+
*/
|
|
39
|
+
declare function omit<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean)): Record<string, TValue>;
|
|
24
40
|
declare const _default: {
|
|
25
41
|
isEmptyObject: typeof isEmptyObject;
|
|
26
42
|
fastMerge: typeof fastMerge;
|
|
27
43
|
formatActionName: typeof formatActionName;
|
|
28
44
|
removeNestedNullValues: typeof removeNestedNullValues;
|
|
29
45
|
checkCompatibilityWithExistingValue: typeof checkCompatibilityWithExistingValue;
|
|
46
|
+
pick: typeof pick;
|
|
47
|
+
omit: typeof omit;
|
|
30
48
|
};
|
|
31
49
|
export default _default;
|
package/dist/utils.js
CHANGED
|
@@ -118,4 +118,53 @@ function checkCompatibilityWithExistingValue(value, existingValue) {
|
|
|
118
118
|
isCompatible: true,
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Filters an object based on a condition and an inclusion flag.
|
|
123
|
+
*
|
|
124
|
+
* @param obj - The object to filter.
|
|
125
|
+
* @param condition - The condition to apply.
|
|
126
|
+
* @param include - If true, include entries that match the condition; otherwise, exclude them.
|
|
127
|
+
* @returns The filtered object.
|
|
128
|
+
*/
|
|
129
|
+
function filterObject(obj, condition, include) {
|
|
130
|
+
const result = {};
|
|
131
|
+
const entries = Object.entries(obj);
|
|
132
|
+
for (let i = 0; i < entries.length; i++) {
|
|
133
|
+
const [key, value] = entries[i];
|
|
134
|
+
let shouldInclude;
|
|
135
|
+
if (Array.isArray(condition)) {
|
|
136
|
+
shouldInclude = condition.includes(key);
|
|
137
|
+
}
|
|
138
|
+
else if (typeof condition === 'string') {
|
|
139
|
+
shouldInclude = key === condition;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
shouldInclude = condition(entries[i]);
|
|
143
|
+
}
|
|
144
|
+
if (include ? shouldInclude : !shouldInclude) {
|
|
145
|
+
result[key] = value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Picks entries from an object based on a condition.
|
|
152
|
+
*
|
|
153
|
+
* @param obj - The object to pick entries from.
|
|
154
|
+
* @param condition - The condition to determine which entries to pick.
|
|
155
|
+
* @returns The object containing only the picked entries.
|
|
156
|
+
*/
|
|
157
|
+
function pick(obj, condition) {
|
|
158
|
+
return filterObject(obj, condition, true);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Omits entries from an object based on a condition.
|
|
162
|
+
*
|
|
163
|
+
* @param obj - The object to omit entries from.
|
|
164
|
+
* @param condition - The condition to determine which entries to omit.
|
|
165
|
+
* @returns The object containing only the remaining entries after omission.
|
|
166
|
+
*/
|
|
167
|
+
function omit(obj, condition) {
|
|
168
|
+
return filterObject(obj, condition, false);
|
|
169
|
+
}
|
|
170
|
+
exports.default = { isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue, pick, omit };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a higher order component that provides the ability to map a state property directly to
|
|
3
|
+
* something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
|
|
4
|
+
* will automatically change to reflect the new data.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { MapOnyxToState } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Use `useOnyx` instead of `withOnyx` whenever possible.
|
|
10
|
+
*
|
|
11
|
+
* This is a higher order component that provides the ability to map a state property directly to
|
|
12
|
+
* something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
|
|
13
|
+
* will automatically change to reflect the new data.
|
|
14
|
+
*/
|
|
15
|
+
export default function <TComponentProps, TOnyxProps>(mapOnyxToState: MapOnyxToState<TComponentProps, TOnyxProps>, shouldDelayUpdates?: boolean): (component: React.ComponentType<TComponentProps>) => React.ComponentType<Omit<TComponentProps, keyof TOnyxProps>>;
|
|
@@ -31,21 +31,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
31
31
|
* something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
|
|
32
32
|
* will automatically change to reflect the new data.
|
|
33
33
|
*/
|
|
34
|
-
const prop_types_1 = __importDefault(require("prop-types"));
|
|
35
34
|
const react_1 = __importDefault(require("react"));
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const Str = __importStar(require("
|
|
39
|
-
const utils_1 = __importDefault(require("
|
|
40
|
-
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
35
|
+
const Onyx_1 = __importDefault(require("../Onyx"));
|
|
36
|
+
const OnyxUtils_1 = __importDefault(require("../OnyxUtils"));
|
|
37
|
+
const Str = __importStar(require("../Str"));
|
|
38
|
+
const utils_1 = __importDefault(require("../utils"));
|
|
41
39
|
// 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
|
|
42
40
|
// if a key has changed, it's a good idea to skip looking at these properties since they would have unexpected results.
|
|
43
41
|
const mappingPropertiesToIgnoreChangesTo = ['initialValue', 'allowStaleData'];
|
|
44
42
|
/**
|
|
45
43
|
* Returns the display name of a component
|
|
46
|
-
*
|
|
47
|
-
* @param {object} component
|
|
48
|
-
* @returns {string}
|
|
49
44
|
*/
|
|
50
45
|
function getDisplayName(component) {
|
|
51
46
|
return component.displayName || component.name || 'Component';
|
|
@@ -53,17 +48,28 @@ function getDisplayName(component) {
|
|
|
53
48
|
/**
|
|
54
49
|
* Removes all the keys from state that are unrelated to the onyx data being mapped to the component.
|
|
55
50
|
*
|
|
56
|
-
* @param
|
|
57
|
-
* @param
|
|
58
|
-
|
|
51
|
+
* @param state of the component
|
|
52
|
+
* @param onyxToStateMapping the object holding all of the mapping configuration for the component
|
|
53
|
+
*/
|
|
54
|
+
function getOnyxDataFromState(state, onyxToStateMapping) {
|
|
55
|
+
return utils_1.default.pick(state, Object.keys(onyxToStateMapping));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Utility function to return the properly typed entries of the `withOnyx` mapping object.
|
|
59
|
+
*/
|
|
60
|
+
function mapOnyxToStateEntries(mapOnyxToState) {
|
|
61
|
+
return Object.entries(mapOnyxToState);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @deprecated Use `useOnyx` instead of `withOnyx` whenever possible.
|
|
65
|
+
*
|
|
66
|
+
* This is a higher order component that provides the ability to map a state property directly to
|
|
67
|
+
* something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
|
|
68
|
+
* will automatically change to reflect the new data.
|
|
59
69
|
*/
|
|
60
|
-
const getOnyxDataFromState = (state, onyxToStateMapping) => underscore_1.default.pick(state, underscore_1.default.keys(onyxToStateMapping));
|
|
61
70
|
function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
62
71
|
// A list of keys that must be present in tempState before we can render the WrappedComponent
|
|
63
|
-
const requiredKeysForInit =
|
|
64
|
-
.omit((config) => config.initWithStoredValues === false)
|
|
65
|
-
.keys()
|
|
66
|
-
.value();
|
|
72
|
+
const requiredKeysForInit = Object.keys(utils_1.default.omit(mapOnyxToState, ([, options]) => options.initWithStoredValues === false));
|
|
67
73
|
return (WrappedComponent) => {
|
|
68
74
|
const displayName = getDisplayName(WrappedComponent);
|
|
69
75
|
class withOnyx extends react_1.default.Component {
|
|
@@ -76,7 +82,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
76
82
|
// This stores all the Onyx connection IDs to be used when the component unmounts so everything can be
|
|
77
83
|
// disconnected. It is a key value store with the format {[mapping.key]: connectionID}.
|
|
78
84
|
this.activeConnectionIDs = {};
|
|
79
|
-
const cachedState =
|
|
85
|
+
const cachedState = mapOnyxToStateEntries(mapOnyxToState).reduce((resultObj, [propName, mapping]) => {
|
|
80
86
|
const key = Str.result(mapping.key, props);
|
|
81
87
|
let value = OnyxUtils_1.default.tryGetCachedValue(key, mapping);
|
|
82
88
|
if (!value && mapping.initialValue) {
|
|
@@ -95,12 +101,12 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
95
101
|
*/
|
|
96
102
|
if (mapping.initWithStoredValues !== false && ((value !== undefined && !OnyxUtils_1.default.hasPendingMergeForKey(key)) || mapping.allowStaleData)) {
|
|
97
103
|
// eslint-disable-next-line no-param-reassign
|
|
98
|
-
resultObj[
|
|
104
|
+
resultObj[propName] = value;
|
|
99
105
|
}
|
|
100
106
|
return resultObj;
|
|
101
107
|
}, {});
|
|
102
108
|
// If we have all the data we need, then we can render the component immediately
|
|
103
|
-
cachedState.loading =
|
|
109
|
+
cachedState.loading = Object.keys(cachedState).length < requiredKeysForInit.length;
|
|
104
110
|
// Object holding the temporary initial state for the component while we load the various Onyx keys
|
|
105
111
|
this.tempState = cachedState;
|
|
106
112
|
this.state = cachedState;
|
|
@@ -108,12 +114,12 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
108
114
|
componentDidMount() {
|
|
109
115
|
const onyxDataFromState = getOnyxDataFromState(this.state, mapOnyxToState);
|
|
110
116
|
// Subscribe each of the state properties to the proper Onyx key
|
|
111
|
-
|
|
112
|
-
if (
|
|
117
|
+
mapOnyxToStateEntries(mapOnyxToState).forEach(([propName, mapping]) => {
|
|
118
|
+
if (mappingPropertiesToIgnoreChangesTo.includes(propName)) {
|
|
113
119
|
return;
|
|
114
120
|
}
|
|
115
121
|
const key = Str.result(mapping.key, Object.assign(Object.assign({}, this.props), onyxDataFromState));
|
|
116
|
-
this.connectMappingToOnyx(mapping,
|
|
122
|
+
this.connectMappingToOnyx(mapping, propName, key);
|
|
117
123
|
});
|
|
118
124
|
this.checkEvictableKeys();
|
|
119
125
|
}
|
|
@@ -124,9 +130,9 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
124
130
|
const isFirstTimeUpdatingAfterLoading = prevState.loading && !this.state.loading;
|
|
125
131
|
const onyxDataFromState = getOnyxDataFromState(this.state, mapOnyxToState);
|
|
126
132
|
const prevOnyxDataFromState = getOnyxDataFromState(prevState, mapOnyxToState);
|
|
127
|
-
|
|
133
|
+
mapOnyxToStateEntries(mapOnyxToState).forEach(([propName, mapping]) => {
|
|
128
134
|
// Some properties can be ignored because they aren't related to onyx keys and they will never change
|
|
129
|
-
if (
|
|
135
|
+
if (mappingPropertiesToIgnoreChangesTo.includes(propName)) {
|
|
130
136
|
return;
|
|
131
137
|
}
|
|
132
138
|
// The previous key comes from either:
|
|
@@ -148,7 +154,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
148
154
|
}
|
|
149
155
|
componentWillUnmount() {
|
|
150
156
|
// Disconnect everything from Onyx
|
|
151
|
-
|
|
157
|
+
mapOnyxToStateEntries(mapOnyxToState).forEach(([, mapping]) => {
|
|
152
158
|
const key = Str.result(mapping.key, Object.assign(Object.assign({}, this.props), getOnyxDataFromState(this.state, mapOnyxToState)));
|
|
153
159
|
Onyx_1.default.disconnect(this.activeConnectionIDs[key], key);
|
|
154
160
|
});
|
|
@@ -175,9 +181,6 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
175
181
|
* We however need to workaround this issue in the HOC. The addition of initialValue makes things even more complex,
|
|
176
182
|
* since you cannot be really sure if the component has been updated before or after the initial hydration. Therefore if
|
|
177
183
|
* initialValue is there, we just check if the update is different than that and then try to handle it as best as we can.
|
|
178
|
-
*
|
|
179
|
-
* @param {String} statePropertyName
|
|
180
|
-
* @param {*} val
|
|
181
184
|
*/
|
|
182
185
|
setWithOnyxState(statePropertyName, val) {
|
|
183
186
|
const prevValue = this.state[statePropertyName];
|
|
@@ -198,7 +201,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
198
201
|
}
|
|
199
202
|
this.tempState[statePropertyName] = val;
|
|
200
203
|
// If some key does not have a value yet, do not update the state yet
|
|
201
|
-
const tempStateIsMissingKey =
|
|
204
|
+
const tempStateIsMissingKey = requiredKeysForInit.some((key) => { var _a; return ((_a = this.tempState) === null || _a === void 0 ? void 0 : _a[key]) === undefined; });
|
|
202
205
|
if (tempStateIsMissingKey) {
|
|
203
206
|
return;
|
|
204
207
|
}
|
|
@@ -206,25 +209,26 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
206
209
|
delete this.tempState;
|
|
207
210
|
// Full of hacky workarounds to prevent the race condition described above.
|
|
208
211
|
this.setState((prevState) => {
|
|
209
|
-
const finalState =
|
|
212
|
+
const finalState = Object.keys(stateUpdate).reduce((result, _key) => {
|
|
213
|
+
const key = _key;
|
|
210
214
|
if (key === 'loading') {
|
|
211
215
|
return result;
|
|
212
216
|
}
|
|
213
217
|
const initialValue = mapOnyxToState[key].initialValue;
|
|
214
218
|
// If initialValue is there and the state contains something different it means
|
|
215
219
|
// an update has already been received and we can discard the value we are trying to hydrate
|
|
216
|
-
if (
|
|
220
|
+
if (initialValue !== undefined && prevState[key] !== undefined && prevState[key] !== initialValue) {
|
|
217
221
|
// eslint-disable-next-line no-param-reassign
|
|
218
222
|
result[key] = prevState[key];
|
|
219
223
|
// if value is already there (without initial value) then we can discard the value we are trying to hydrate
|
|
220
224
|
}
|
|
221
|
-
else if (
|
|
225
|
+
else if (prevState[key] !== undefined) {
|
|
222
226
|
// eslint-disable-next-line no-param-reassign
|
|
223
227
|
result[key] = prevState[key];
|
|
224
228
|
}
|
|
225
229
|
else {
|
|
226
230
|
// eslint-disable-next-line no-param-reassign
|
|
227
|
-
result[key] =
|
|
231
|
+
result[key] = stateUpdate[key];
|
|
228
232
|
}
|
|
229
233
|
return result;
|
|
230
234
|
}, {});
|
|
@@ -241,11 +245,11 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
241
245
|
// We will add this key to our list of recently accessed keys
|
|
242
246
|
// if the canEvict function returns true. This is necessary criteria
|
|
243
247
|
// we MUST use to specify if a key can be removed or not.
|
|
244
|
-
|
|
245
|
-
if (
|
|
248
|
+
mapOnyxToStateEntries(mapOnyxToState).forEach(([, mapping]) => {
|
|
249
|
+
if (mapping.canEvict === undefined) {
|
|
246
250
|
return;
|
|
247
251
|
}
|
|
248
|
-
const canEvict = Str.result(mapping.canEvict, this.props);
|
|
252
|
+
const canEvict = !!Str.result(mapping.canEvict, this.props);
|
|
249
253
|
const key = Str.result(mapping.key, this.props);
|
|
250
254
|
if (!OnyxUtils_1.default.isSafeEvictionKey(key)) {
|
|
251
255
|
throw new Error(`canEvict can't be used on key '${key}'. This key must explicitly be flagged as safe for removal by adding it to Onyx.init({safeEvictionKeys: []}).`);
|
|
@@ -261,22 +265,21 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
261
265
|
/**
|
|
262
266
|
* Takes a single mapping and binds the state of the component to the store
|
|
263
267
|
*
|
|
264
|
-
* @param
|
|
265
|
-
* @param {string|function} mapping.key key to connect to. can be a string or a
|
|
268
|
+
* @param mapping.key key to connect to. can be a string or a
|
|
266
269
|
* function that takes this.props as an argument and returns a string
|
|
267
|
-
* @param
|
|
268
|
-
* @param
|
|
270
|
+
* @param statePropertyName the name of the state property that Onyx will add the data to
|
|
271
|
+
* @param [mapping.initWithStoredValues] If set to false, then no data will be prefilled into the
|
|
269
272
|
* component
|
|
270
|
-
* @param
|
|
273
|
+
* @param key to connect to Onyx with
|
|
271
274
|
*/
|
|
272
275
|
connectMappingToOnyx(mapping, statePropertyName, key) {
|
|
276
|
+
const onyxMapping = mapOnyxToState[statePropertyName];
|
|
273
277
|
// Remember what the previous key was so that key changes can be detected when data is being loaded from Onyx. This will allow
|
|
274
278
|
// dependent keys to finish loading their data.
|
|
275
279
|
// eslint-disable-next-line no-param-reassign
|
|
276
|
-
|
|
280
|
+
onyxMapping.previousKey = key;
|
|
277
281
|
// eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs
|
|
278
|
-
this.activeConnectionIDs[key] = Onyx_1.default.connect(Object.assign(Object.assign({}, mapping), { key,
|
|
279
|
-
statePropertyName, withOnyxInstance: this, displayName }));
|
|
282
|
+
this.activeConnectionIDs[key] = Onyx_1.default.connect(Object.assign(Object.assign({}, mapping), { key, statePropertyName: statePropertyName, withOnyxInstance: this, displayName }));
|
|
280
283
|
}
|
|
281
284
|
flushPendingSetStates() {
|
|
282
285
|
if (!this.shouldDelayUpdates) {
|
|
@@ -290,29 +293,18 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
290
293
|
}
|
|
291
294
|
render() {
|
|
292
295
|
// Remove any null values so that React replaces them with default props
|
|
293
|
-
const propsToPass =
|
|
296
|
+
const propsToPass = utils_1.default.omit(this.props, ([, propValue]) => propValue === null);
|
|
294
297
|
if (this.state.loading) {
|
|
295
298
|
return null;
|
|
296
299
|
}
|
|
297
300
|
// Remove any internal state properties used by withOnyx
|
|
298
301
|
// that should not be passed to a wrapped component
|
|
299
|
-
|
|
300
|
-
stateToPass = underscore_1.default.omit(stateToPass, underscore_1.default.isNull);
|
|
302
|
+
const stateToPass = utils_1.default.omit(this.state, ([stateKey, stateValue]) => stateKey === 'loading' || stateValue === null);
|
|
301
303
|
const stateToPassWithoutNestedNulls = utils_1.default.removeNestedNullValues(stateToPass);
|
|
302
304
|
// Spreading props and state is necessary in an HOC where the data cannot be predicted
|
|
303
305
|
return (react_1.default.createElement(WrappedComponent, Object.assign({ markReadyForHydration: this.flushPendingSetStates }, propsToPass, stateToPassWithoutNestedNulls, { ref: this.props.forwardedRef })));
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
|
-
withOnyx.propTypes = {
|
|
307
|
-
forwardedRef: prop_types_1.default.oneOfType([
|
|
308
|
-
prop_types_1.default.func,
|
|
309
|
-
// eslint-disable-next-line react/forbid-prop-types
|
|
310
|
-
prop_types_1.default.shape({ current: prop_types_1.default.object }),
|
|
311
|
-
]),
|
|
312
|
-
};
|
|
313
|
-
withOnyx.defaultProps = {
|
|
314
|
-
forwardedRef: undefined,
|
|
315
|
-
};
|
|
316
308
|
withOnyx.displayName = `withOnyx(${displayName})`;
|
|
317
309
|
return react_1.default.forwardRef((props, ref) => {
|
|
318
310
|
const Component = withOnyx;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import type { ForwardedRef } from 'react';
|
|
2
|
+
import type { IsEqual } from 'type-fest';
|
|
3
|
+
import type { CollectionKeyBase, ExtractOnyxCollectionValue, KeyValueMapping, NullableKeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector } from '../types';
|
|
4
4
|
/**
|
|
5
5
|
* Represents the base mapping options between an Onyx key and the component's prop.
|
|
6
6
|
*/
|
|
@@ -9,15 +9,18 @@ type BaseMapping<TComponentProps, TOnyxProps> = {
|
|
|
9
9
|
initWithStoredValues?: boolean;
|
|
10
10
|
allowStaleData?: boolean;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Represents the base mapping options when an Onyx collection key is supplied.
|
|
14
|
+
*/
|
|
13
15
|
type CollectionBaseMapping<TOnyxKey extends CollectionKeyBase> = {
|
|
14
16
|
initialValue?: OnyxCollection<KeyValueMapping[TOnyxKey]>;
|
|
15
17
|
};
|
|
16
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Represents the base mapping options when an Onyx non-collection key is supplied.
|
|
20
|
+
*/
|
|
17
21
|
type EntryBaseMapping<TOnyxKey extends OnyxKey> = {
|
|
18
22
|
initialValue?: OnyxEntry<KeyValueMapping[TOnyxKey]>;
|
|
19
23
|
};
|
|
20
|
-
|
|
21
24
|
/**
|
|
22
25
|
* Represents the string / function `key` mapping option between an Onyx key and the component's prop.
|
|
23
26
|
*
|
|
@@ -40,12 +43,9 @@ type EntryBaseMapping<TOnyxKey extends OnyxKey> = {
|
|
|
40
43
|
* },
|
|
41
44
|
* ```
|
|
42
45
|
*/
|
|
43
|
-
type BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey, TOnyxValue> = IsEqual<TOnyxValue, TOnyxProps[TOnyxProp]> extends true
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
: never;
|
|
48
|
-
|
|
46
|
+
type BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey, TOnyxValue> = IsEqual<TOnyxValue, TOnyxProps[TOnyxProp]> extends true ? {
|
|
47
|
+
key: TOnyxKey | ((props: Omit<TComponentProps, keyof TOnyxProps> & Partial<TOnyxProps>) => TOnyxKey);
|
|
48
|
+
} : never;
|
|
49
49
|
/**
|
|
50
50
|
* Represents the string `key` and `selector` mapping options between an Onyx key and the component's prop.
|
|
51
51
|
*
|
|
@@ -65,7 +65,6 @@ type BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TReturnType, T
|
|
|
65
65
|
key: TOnyxKey;
|
|
66
66
|
selector: Selector<TOnyxKey, TOnyxProps, TReturnType>;
|
|
67
67
|
};
|
|
68
|
-
|
|
69
68
|
/**
|
|
70
69
|
* Represents the function `key` and `selector` mapping options between an Onyx key and the component's prop.
|
|
71
70
|
*
|
|
@@ -85,29 +84,21 @@ type BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TReturnType,
|
|
|
85
84
|
key: (props: Omit<TComponentProps, keyof TOnyxProps> & Partial<TOnyxProps>) => TOnyxKey;
|
|
86
85
|
selector: Selector<TOnyxKey, TOnyxProps, TReturnType>;
|
|
87
86
|
};
|
|
88
|
-
|
|
89
87
|
/**
|
|
90
88
|
* Represents the mapping options between an Onyx key and the component's prop with all its possibilities.
|
|
91
89
|
*/
|
|
92
|
-
type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey> = BaseMapping<TComponentProps, TOnyxProps> &
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey> = BaseMapping<TComponentProps, TOnyxProps> & EntryBaseMapping<TOnyxKey> & (BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxEntry<KeyValueMapping[TOnyxKey]>> | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey>);
|
|
91
|
+
/**
|
|
92
|
+
* Represents a superset of `Mapping` type with internal properties included.
|
|
93
|
+
*/
|
|
94
|
+
type WithOnyxMapping<TComponentProps, TOnyxProps> = Mapping<TComponentProps, TOnyxProps, keyof TOnyxProps, OnyxKey> & {
|
|
95
|
+
connectionID: number;
|
|
96
|
+
previousKey?: OnyxKey;
|
|
97
|
+
};
|
|
100
98
|
/**
|
|
101
99
|
* Represents the mapping options between an Onyx collection key without suffix and the component's prop with all its possibilities.
|
|
102
100
|
*/
|
|
103
|
-
type CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends CollectionKeyBase> = BaseMapping<TComponentProps, TOnyxProps> &
|
|
104
|
-
CollectionBaseMapping<TOnyxKey> &
|
|
105
|
-
(
|
|
106
|
-
| BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>>
|
|
107
|
-
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey>
|
|
108
|
-
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey>
|
|
109
|
-
);
|
|
110
|
-
|
|
101
|
+
type CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends CollectionKeyBase> = BaseMapping<TComponentProps, TOnyxProps> & CollectionBaseMapping<TOnyxKey> & (BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>> | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey>);
|
|
111
102
|
/**
|
|
112
103
|
* Represents an union type of all the possible Onyx key mappings.
|
|
113
104
|
* Each `OnyxPropMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
|
|
@@ -115,7 +106,6 @@ type CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOny
|
|
|
115
106
|
type OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
|
|
116
107
|
[TOnyxKey in OnyxKey]: Mapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
|
|
117
108
|
}[OnyxKey];
|
|
118
|
-
|
|
119
109
|
/**
|
|
120
110
|
* Represents an union type of all the possible Onyx collection keys without suffix mappings.
|
|
121
111
|
* Each `OnyxPropCollectionMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
|
|
@@ -123,19 +113,29 @@ type OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxP
|
|
|
123
113
|
type OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
|
|
124
114
|
[TOnyxKey in CollectionKeyBase]: CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
|
|
125
115
|
}[CollectionKeyBase];
|
|
126
|
-
|
|
127
116
|
/**
|
|
128
|
-
*
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
117
|
+
* Represents an Onyx mapping object that connects Onyx keys to component's props.
|
|
118
|
+
*/
|
|
119
|
+
type MapOnyxToState<TComponentProps, TOnyxProps> = {
|
|
120
|
+
[TOnyxProp in keyof TOnyxProps]: OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp> | OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp>;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Represents the `withOnyx` internal component props.
|
|
124
|
+
*/
|
|
125
|
+
type WithOnyxProps<TComponentProps, TOnyxProps> = Omit<TComponentProps, keyof TOnyxProps> & {
|
|
126
|
+
forwardedRef?: ForwardedRef<unknown>;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Represents the `withOnyx` internal component state.
|
|
133
130
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
type WithOnyxState<TOnyxProps> = TOnyxProps & {
|
|
132
|
+
loading: boolean;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Represents the `withOnyx` internal component instance.
|
|
136
|
+
*/
|
|
137
|
+
type WithOnyxInstance = React.Component<unknown, WithOnyxState<NullableKeyValueMapping>> & {
|
|
138
|
+
setStateProxy: (modifier: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>> | ((state: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>>) => OnyxValue<OnyxKey>)) => void;
|
|
139
|
+
setWithOnyxState: (statePropertyName: OnyxKey, value: OnyxValue<OnyxKey>) => void;
|
|
140
|
+
};
|
|
141
|
+
export type { WithOnyxMapping, MapOnyxToState, WithOnyxProps, WithOnyxInstance, WithOnyxState };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.42",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"lint": "eslint .",
|
|
32
32
|
"typecheck": "tsc --noEmit",
|
|
33
33
|
"test": "jest",
|
|
34
|
-
"build": "tsc -p tsconfig.build.json
|
|
34
|
+
"build": "tsc -p tsconfig.build.json",
|
|
35
35
|
"build:watch": "nodemon --watch lib --ext js,json,ts,tsx --exec \"npm run build && npm pack\"",
|
|
36
36
|
"prebuild:docs": "npm run build",
|
|
37
37
|
"build:docs": "ts-node buildDocs.ts",
|