react-native-onyx 2.0.41 → 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.
@@ -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 { OnyxUpdate, ConnectOptions } from './Onyx';
3
- import type { CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, OnyxValue } from './types';
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 { withOnyx, useOnyx };
9
- export type { CustomTypeOptions, OnyxCollection, OnyxEntry, OnyxUpdate, ConnectOptions, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, UseOnyxResult, OnyxValue, FetchStatus, ResultMetadata, };
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.useOnyx = exports.withOnyx = void 0;
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: WithOnyxInstanceState<TOnyxProps>) => TReturnType;
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
- export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, WithOnyxInstance, WithOnyxInstanceState, };
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/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
- exports.default = { isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue };
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 underscore_1 = __importDefault(require("underscore"));
37
- const Onyx_1 = __importDefault(require("./Onyx"));
38
- const Str = __importStar(require("./Str"));
39
- const utils_1 = __importDefault(require("./utils"));
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 {Object} state of the component
57
- * @param {Object} onyxToStateMapping the object holding all of the mapping configuration for the component
58
- * @returns {Object}
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 = underscore_1.default.chain(mapOnyxToState)
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 = underscore_1.default.reduce(mapOnyxToState, (resultObj, mapping, propertyName) => {
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[propertyName] = value;
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 = underscore_1.default.size(cachedState) < requiredKeysForInit.length;
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
- underscore_1.default.each(mapOnyxToState, (mapping, propertyName) => {
112
- if (underscore_1.default.includes(mappingPropertiesToIgnoreChangesTo, propertyName)) {
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, propertyName, key);
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
- underscore_1.default.each(mapOnyxToState, (mapping, propName) => {
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 (underscore_1.default.includes(mappingPropertiesToIgnoreChangesTo, propName)) {
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
- underscore_1.default.each(mapOnyxToState, (mapping) => {
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 = underscore_1.default.some(requiredKeysForInit, (key) => underscore_1.default.isUndefined(this.tempState[key]));
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 = underscore_1.default.reduce(stateUpdate, (result, value, key) => {
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 (!underscore_1.default.isUndefined(initialValue) && !underscore_1.default.isUndefined(prevState[key]) && prevState[key] !== initialValue) {
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 (!underscore_1.default.isUndefined(prevState[key])) {
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] = value;
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
- underscore_1.default.each(mapOnyxToState, (mapping) => {
245
- if (underscore_1.default.isUndefined(mapping.canEvict)) {
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 {object} mapping
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 {string} statePropertyName the name of the state property that Onyx will add the data to
268
- * @param {boolean} [mapping.initWithStoredValues] If set to false, then no data will be prefilled into the
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 {string} key to connect to Onyx with
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
- mapOnyxToState[statePropertyName].previousKey = key;
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 = underscore_1.default.omit(this.props, underscore_1.default.isNull);
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
- let stateToPass = underscore_1.default.omit(this.state, 'loading');
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 {IsEqual} from 'type-fest';
2
- import {CollectionKeyBase, ExtractOnyxCollectionValue, KeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, Selector} from './types';
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
- key: TOnyxKey | ((props: Omit<TComponentProps, keyof TOnyxProps> & Partial<TOnyxProps>) => TOnyxKey);
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
- EntryBaseMapping<TOnyxKey> &
94
- (
95
- | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxEntry<KeyValueMapping[TOnyxKey]>>
96
- | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey>
97
- | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey>
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
- * @deprecated Use `useOnyx` instead of `withOnyx` whenever possible.
129
- *
130
- * This is a higher order component that provides the ability to map a state property directly to
131
- * something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
132
- * will automatically change to reflect the new data.
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
- declare function withOnyx<TComponentProps, TOnyxProps>(
135
- mapping: {
136
- [TOnyxProp in keyof TOnyxProps]: OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp> | OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp>;
137
- },
138
- shouldDelayUpdates?: boolean,
139
- ): (component: React.ComponentType<TComponentProps>) => React.ComponentType<Omit<TComponentProps, keyof TOnyxProps>>;
140
-
141
- export default withOnyx;
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 };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.41",
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 && cp ./lib/*.d.ts ./dist",
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",