react-native-onyx 2.0.63 → 2.0.65

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/types.d.ts CHANGED
@@ -226,29 +226,34 @@ type Collection<TKey extends CollectionKeyBase, TValue, TMap = never> = {
226
226
  };
227
227
  /** Represents the base options used in `Onyx.connect()` method. */
228
228
  type BaseConnectOptions = {
229
+ /** If set to `false`, then the initial data will be only sent to the callback function if it changes. */
229
230
  initWithStoredValues?: boolean;
231
+ /**
232
+ * If set to `false`, the connection won't be reused between other subscribers that are listening to the same Onyx key
233
+ * with the same connect configurations.
234
+ */
235
+ reuseConnection?: boolean;
230
236
  };
231
- /** Represents additional options used inside withOnyx HOC */
232
- type WithOnyxConnectOptions<TKey extends OnyxKey> = {
233
- withOnyxInstance: WithOnyxInstance;
234
- statePropertyName: string;
235
- displayName: string;
236
- initWithStoredValues?: boolean;
237
- selector?: Selector<TKey, unknown, unknown>;
238
- canEvict?: boolean;
239
- };
240
- type DefaultConnectCallback<TKey extends OnyxKey> = (value: OnyxEntry<KeyValueMapping[TKey]>, key: TKey) => void;
241
- type CollectionConnectCallback<TKey extends OnyxKey> = (value: NonUndefined<OnyxCollection<KeyValueMapping[TKey]>>) => void;
242
237
  /** Represents the callback function used in `Onyx.connect()` method with a regular key. */
243
- type DefaultConnectOptions<TKey extends OnyxKey> = {
238
+ type DefaultConnectCallback<TKey extends OnyxKey> = (value: OnyxEntry<KeyValueMapping[TKey]>, key: TKey) => void;
239
+ /** Represents the callback function used in `Onyx.connect()` method with a collection key. */
240
+ type CollectionConnectCallback<TKey extends OnyxKey> = (value: NonUndefined<OnyxCollection<KeyValueMapping[TKey]>>, key: TKey) => void;
241
+ /** Represents the options used in `Onyx.connect()` method with a regular key. */
242
+ type DefaultConnectOptions<TKey extends OnyxKey> = BaseConnectOptions & {
243
+ /** The Onyx key to subscribe to. */
244
244
  key: TKey;
245
+ /** A function that will be called when the Onyx data we are subscribed changes. */
245
246
  callback?: DefaultConnectCallback<TKey>;
247
+ /** If set to `true`, it will return the entire collection to the callback as a single object. */
246
248
  waitForCollectionCallback?: false;
247
249
  };
248
- /** Represents the callback function used in `Onyx.connect()` method with a collection key. */
249
- type CollectionConnectOptions<TKey extends OnyxKey> = {
250
+ /** Represents the options used in `Onyx.connect()` method with a collection key. */
251
+ type CollectionConnectOptions<TKey extends OnyxKey> = BaseConnectOptions & {
252
+ /** The Onyx key to subscribe to. */
250
253
  key: TKey extends CollectionKeyBase ? TKey : never;
254
+ /** A function that will be called when the Onyx data we are subscribed changes. */
251
255
  callback?: CollectionConnectCallback<TKey>;
256
+ /** If set to `true`, it will return the entire collection to the callback as a single object. */
252
257
  waitForCollectionCallback: true;
253
258
  };
254
259
  /**
@@ -261,12 +266,28 @@ type CollectionConnectOptions<TKey extends OnyxKey> = {
261
266
  *
262
267
  * If `waitForCollectionCallback` is `false` or not specified, the `key` can be any Onyx key and `callback` will be triggered with updates of each collection item
263
268
  * and will pass `value` as an `OnyxEntry`.
264
- *
265
- * The type is also extended with `BaseConnectOptions` and `WithOnyxConnectOptions` to include additional options, depending on the context where it's used.
266
269
  */
267
- type ConnectOptions<TKey extends OnyxKey> = (CollectionConnectOptions<TKey> | DefaultConnectOptions<TKey>) & (BaseConnectOptions | WithOnyxConnectOptions<TKey>);
268
- type Mapping<TKey extends OnyxKey> = ConnectOptions<TKey> & {
269
- connectionID: number;
270
+ type ConnectOptions<TKey extends OnyxKey> = DefaultConnectOptions<TKey> | CollectionConnectOptions<TKey>;
271
+ /** Represents additional `Onyx.connect()` options used inside `withOnyx()` HOC. */
272
+ type WithOnyxConnectOptions<TKey extends OnyxKey> = ConnectOptions<TKey> & {
273
+ /** The `withOnyx` class instance to be internally passed. */
274
+ withOnyxInstance: WithOnyxInstance;
275
+ /** The name of the component's prop that is connected to the Onyx key. */
276
+ statePropertyName: string;
277
+ /** The component's display name. */
278
+ displayName: string;
279
+ /**
280
+ * This will be used to subscribe to a subset of an Onyx key's data.
281
+ * Using this setting on `withOnyx` can have very positive performance benefits because the component will only re-render
282
+ * when the subset of data changes. Otherwise, any change of data on any property would normally
283
+ * cause the component to re-render (and that can be expensive from a performance standpoint).
284
+ */
285
+ selector?: Selector<TKey, unknown, unknown>;
286
+ /** Determines if this key in this subscription is safe to be evicted. */
287
+ canEvict?: boolean;
288
+ };
289
+ type Mapping<TKey extends OnyxKey> = WithOnyxConnectOptions<TKey> & {
290
+ subscriptionID: number;
270
291
  };
271
292
  /**
272
293
  * Represents a single Onyx input value, that can be either `TOnyxValue` or `null` if the key should be deleted.
package/dist/useOnyx.d.ts CHANGED
@@ -6,11 +6,11 @@ type BaseUseOnyxOptions = {
6
6
  */
7
7
  canEvict?: boolean;
8
8
  /**
9
- * If set to false, then no data will be prefilled into the component.
9
+ * If set to `false`, then no data will be prefilled into the component.
10
10
  */
11
11
  initWithStoredValues?: boolean;
12
12
  /**
13
- * If set to true, data will be retrieved from cache during the first render even if there is a pending merge for the key.
13
+ * If set to `true`, data will be retrieved from cache during the first render even if there is a pending merge for the key.
14
14
  */
15
15
  allowStaleData?: boolean;
16
16
  };
package/dist/useOnyx.js CHANGED
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fast_equals_1 = require("fast-equals");
7
7
  const react_1 = require("react");
8
- const Onyx_1 = __importDefault(require("./Onyx"));
9
8
  const OnyxCache_1 = __importDefault(require("./OnyxCache"));
9
+ const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager"));
10
10
  const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
11
11
  const useLiveRef_1 = __importDefault(require("./useLiveRef"));
12
12
  const usePrevious_1 = __importDefault(require("./usePrevious"));
@@ -15,7 +15,7 @@ function getCachedValue(key, selector) {
15
15
  return ((_a = OnyxUtils_1.default.tryGetCachedValue(key, { selector })) !== null && _a !== void 0 ? _a : undefined);
16
16
  }
17
17
  function useOnyx(key, options) {
18
- const connectionIDRef = (0, react_1.useRef)(null);
18
+ const connectionRef = (0, react_1.useRef)(null);
19
19
  const previousKey = (0, usePrevious_1.default)(key);
20
20
  // Used to stabilize the selector reference and avoid unnecessary calls to `getSnapshot()`.
21
21
  const selectorRef = (0, useLiveRef_1.default)(options === null || options === void 0 ? void 0 : options.selector);
@@ -57,6 +57,21 @@ function useOnyx(key, options) {
57
57
  }
58
58
  throw new Error(`'${previousKey}' key can't be changed to '${key}'. useOnyx() only supports dynamic keys if they are both collection member keys from the same collection e.g. from 'collection_id1' to 'collection_id2'.`);
59
59
  }, [previousKey, key]);
60
+ // Mimics withOnyx's checkEvictableKeys() behavior.
61
+ const checkEvictableKey = (0, react_1.useCallback)(() => {
62
+ if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionRef.current) {
63
+ return;
64
+ }
65
+ if (!OnyxUtils_1.default.isSafeEvictionKey(key)) {
66
+ 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: []}).`);
67
+ }
68
+ if (options.canEvict) {
69
+ OnyxConnectionManager_1.default.removeFromEvictionBlockList(connectionRef.current);
70
+ }
71
+ else {
72
+ OnyxConnectionManager_1.default.addToEvictionBlockList(connectionRef.current);
73
+ }
74
+ }, [key, options === null || options === void 0 ? void 0 : options.canEvict]);
60
75
  const getSnapshot = (0, react_1.useCallback)(() => {
61
76
  var _a, _b, _c;
62
77
  // We get the value from cache while the first connection to Onyx is being made,
@@ -110,7 +125,7 @@ function useOnyx(key, options) {
110
125
  return resultRef.current;
111
126
  }, [key, selectorRef, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.initialValue]);
112
127
  const subscribe = (0, react_1.useCallback)((onStoreChange) => {
113
- connectionIDRef.current = Onyx_1.default.connect({
128
+ connectionRef.current = OnyxConnectionManager_1.default.connect({
114
129
  key,
115
130
  callback: () => {
116
131
  // Signals that the first connection was made, so some logics in `getSnapshot()`
@@ -124,29 +139,18 @@ function useOnyx(key, options) {
124
139
  initWithStoredValues: options === null || options === void 0 ? void 0 : options.initWithStoredValues,
125
140
  waitForCollectionCallback: OnyxUtils_1.default.isCollectionKey(key),
126
141
  });
142
+ checkEvictableKey();
127
143
  return () => {
128
- if (!connectionIDRef.current) {
144
+ if (!connectionRef.current) {
129
145
  return;
130
146
  }
131
- Onyx_1.default.disconnect(connectionIDRef.current);
147
+ OnyxConnectionManager_1.default.disconnect(connectionRef.current);
132
148
  isFirstConnectionRef.current = false;
133
149
  };
134
- }, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues]);
135
- // Mimics withOnyx's checkEvictableKeys() behavior.
150
+ }, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, checkEvictableKey]);
136
151
  (0, react_1.useEffect)(() => {
137
- if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionIDRef.current) {
138
- return;
139
- }
140
- if (!OnyxUtils_1.default.isSafeEvictionKey(key)) {
141
- 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: []}).`);
142
- }
143
- if (options.canEvict) {
144
- OnyxUtils_1.default.removeFromEvictionBlockList(key, connectionIDRef.current);
145
- }
146
- else {
147
- OnyxUtils_1.default.addToEvictionBlockList(key, connectionIDRef.current);
148
- }
149
- }, [key, options === null || options === void 0 ? void 0 : options.canEvict]);
152
+ checkEvictableKey();
153
+ }, [checkEvictableKey]);
150
154
  const result = (0, react_1.useSyncExternalStore)(subscribe, getSnapshot);
151
155
  return result;
152
156
  }
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { OnyxInput, OnyxKey } from './types';
1
+ import type { ConnectOptions, OnyxInput, OnyxKey } from './types';
2
2
  type EmptyObject = Record<string, never>;
3
3
  type EmptyValue = EmptyObject | null | undefined;
4
4
  /** Checks whether the given object is an object and not null/undefined. */
@@ -37,6 +37,10 @@ declare function pick<TValue>(obj: Record<string, TValue>, condition: string | s
37
37
  * @returns The object containing only the remaining entries after omission.
38
38
  */
39
39
  declare function omit<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean)): Record<string, TValue>;
40
+ /**
41
+ * Whether the connect options has the `withOnyxInstance` property defined, that is, it's used by the `withOnyx()` HOC.
42
+ */
43
+ declare function hasWithOnyxInstance<TKey extends OnyxKey>(mapping: ConnectOptions<TKey>): unknown;
40
44
  declare const _default: {
41
45
  isEmptyObject: typeof isEmptyObject;
42
46
  fastMerge: typeof fastMerge;
@@ -45,5 +49,6 @@ declare const _default: {
45
49
  checkCompatibilityWithExistingValue: typeof checkCompatibilityWithExistingValue;
46
50
  pick: typeof pick;
47
51
  omit: typeof omit;
52
+ hasWithOnyxInstance: typeof hasWithOnyxInstance;
48
53
  };
49
54
  export default _default;
package/dist/utils.js CHANGED
@@ -170,4 +170,10 @@ function pick(obj, condition) {
170
170
  function omit(obj, condition) {
171
171
  return filterObject(obj, condition, false);
172
172
  }
173
- exports.default = { isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue, pick, omit };
173
+ /**
174
+ * Whether the connect options has the `withOnyxInstance` property defined, that is, it's used by the `withOnyx()` HOC.
175
+ */
176
+ function hasWithOnyxInstance(mapping) {
177
+ return 'withOnyxInstance' in mapping && mapping.withOnyxInstance;
178
+ }
179
+ exports.default = { isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue, pick, omit, hasWithOnyxInstance };
@@ -32,11 +32,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
32
32
  * will automatically change to reflect the new data.
33
33
  */
34
34
  const react_1 = __importDefault(require("react"));
35
- const Onyx_1 = __importDefault(require("../Onyx"));
36
35
  const OnyxUtils_1 = __importDefault(require("../OnyxUtils"));
37
36
  const Str = __importStar(require("../Str"));
38
37
  const utils_1 = __importDefault(require("../utils"));
39
38
  const OnyxCache_1 = __importDefault(require("../OnyxCache"));
39
+ const OnyxConnectionManager_1 = __importDefault(require("../OnyxConnectionManager"));
40
40
  // 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
41
41
  // if a key has changed, it's a good idea to skip looking at these properties since they would have unexpected results.
42
42
  const mappingPropertiesToIgnoreChangesTo = ['initialValue', 'allowStaleData'];
@@ -80,9 +80,9 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
80
80
  this.shouldDelayUpdates = shouldDelayUpdates;
81
81
  this.setWithOnyxState = this.setWithOnyxState.bind(this);
82
82
  this.flushPendingSetStates = this.flushPendingSetStates.bind(this);
83
- // This stores all the Onyx connection IDs to be used when the component unmounts so everything can be
84
- // disconnected. It is a key value store with the format {[mapping.key]: connectionID}.
85
- this.activeConnectionIDs = {};
83
+ // This stores all the Onyx connections to be used when the component unmounts so everything can be
84
+ // disconnected. It is a key value store with the format {[mapping.key]: connection metadata object}.
85
+ this.activeConnections = {};
86
86
  const cachedState = mapOnyxToStateEntries(mapOnyxToState).reduce((resultObj, [propName, mapping]) => {
87
87
  const key = Str.result(mapping.key, props);
88
88
  let value = OnyxUtils_1.default.tryGetCachedValue(key, mapping);
@@ -150,8 +150,8 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
150
150
  const previousKey = isFirstTimeUpdatingAfterLoading ? mapping.previousKey : Str.result(mapping.key, Object.assign(Object.assign({}, prevProps), prevOnyxDataFromState));
151
151
  const newKey = Str.result(mapping.key, Object.assign(Object.assign({}, this.props), onyxDataFromState));
152
152
  if (previousKey !== newKey) {
153
- Onyx_1.default.disconnect(this.activeConnectionIDs[previousKey], previousKey);
154
- delete this.activeConnectionIDs[previousKey];
153
+ OnyxConnectionManager_1.default.disconnect(this.activeConnections[previousKey]);
154
+ delete this.activeConnections[previousKey];
155
155
  this.connectMappingToOnyx(mapping, propName, newKey);
156
156
  }
157
157
  });
@@ -161,7 +161,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
161
161
  // Disconnect everything from Onyx
162
162
  mapOnyxToStateEntries(mapOnyxToState).forEach(([, mapping]) => {
163
163
  const key = Str.result(mapping.key, Object.assign(Object.assign({}, this.props), getOnyxDataFromState(this.state, mapOnyxToState)));
164
- Onyx_1.default.disconnect(this.activeConnectionIDs[key], key);
164
+ OnyxConnectionManager_1.default.disconnect(this.activeConnections[key]);
165
165
  });
166
166
  }
167
167
  setStateProxy(modifier) {
@@ -261,10 +261,10 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
261
261
  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: []}).`);
262
262
  }
263
263
  if (canEvict) {
264
- OnyxUtils_1.default.removeFromEvictionBlockList(key, mapping.connectionID);
264
+ OnyxConnectionManager_1.default.removeFromEvictionBlockList(this.activeConnections[key]);
265
265
  }
266
266
  else {
267
- OnyxUtils_1.default.addToEvictionBlockList(key, mapping.connectionID);
267
+ OnyxConnectionManager_1.default.addToEvictionBlockList(this.activeConnections[key]);
268
268
  }
269
269
  });
270
270
  }
@@ -285,7 +285,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
285
285
  // eslint-disable-next-line no-param-reassign
286
286
  onyxMapping.previousKey = key;
287
287
  // eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs
288
- this.activeConnectionIDs[key] = Onyx_1.default.connect(Object.assign(Object.assign({}, mapping), { key, statePropertyName: statePropertyName, withOnyxInstance: this, displayName }));
288
+ this.activeConnections[key] = OnyxConnectionManager_1.default.connect(Object.assign(Object.assign({}, mapping), { key, statePropertyName: statePropertyName, withOnyxInstance: this, displayName }));
289
289
  }
290
290
  flushPendingSetStates() {
291
291
  if (!this.shouldDelayUpdates) {
@@ -92,7 +92,7 @@ type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TO
92
92
  * Represents a superset of `Mapping` type with internal properties included.
93
93
  */
94
94
  type WithOnyxMapping<TComponentProps, TOnyxProps> = Mapping<TComponentProps, TOnyxProps, keyof TOnyxProps, OnyxKey> & {
95
- connectionID: number;
95
+ subscriptionID: number;
96
96
  previousKey?: OnyxKey;
97
97
  };
98
98
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.63",
3
+ "version": "2.0.65",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",