react-native-onyx 2.0.82 → 2.0.84

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.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library.
3
+ */
4
+ declare const globalSettings: {
5
+ enablePerformanceMetrics: boolean;
6
+ };
7
+ type GlobalSettings = typeof globalSettings;
8
+ declare function addGlobalSettingsChangeListener(listener: (settings: GlobalSettings) => unknown): () => void;
9
+ declare function setPerformanceMetricsEnabled(enabled: boolean): void;
10
+ declare function isPerformanceMetricsEnabled(): boolean;
11
+ export { setPerformanceMetricsEnabled, isPerformanceMetricsEnabled, addGlobalSettingsChangeListener };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addGlobalSettingsChangeListener = exports.isPerformanceMetricsEnabled = exports.setPerformanceMetricsEnabled = void 0;
7
+ const globalSettings = {
8
+ enablePerformanceMetrics: false,
9
+ };
10
+ const listeners = new Set();
11
+ function addGlobalSettingsChangeListener(listener) {
12
+ listeners.add(listener);
13
+ return () => {
14
+ listeners.delete(listener);
15
+ };
16
+ }
17
+ exports.addGlobalSettingsChangeListener = addGlobalSettingsChangeListener;
18
+ function notifyListeners() {
19
+ listeners.forEach((listener) => listener(globalSettings));
20
+ }
21
+ function setPerformanceMetricsEnabled(enabled) {
22
+ globalSettings.enablePerformanceMetrics = enabled;
23
+ notifyListeners();
24
+ }
25
+ exports.setPerformanceMetricsEnabled = setPerformanceMetricsEnabled;
26
+ function isPerformanceMetricsEnabled() {
27
+ return globalSettings.enablePerformanceMetrics;
28
+ }
29
+ exports.isPerformanceMetricsEnabled = isPerformanceMetricsEnabled;
package/dist/Onyx.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as Logger from './Logger';
2
2
  import type { CollectionKeyBase, ConnectOptions, InitOptions, Mapping, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, OnyxUpdate } from './types';
3
3
  import type { Connection } from './OnyxConnectionManager';
4
4
  /** Initialize the store with actions and listening for storage events */
5
- declare function init({ keys, initialKeyStates, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, }: InitOptions): void;
5
+ declare function init({ keys, initialKeyStates, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, enablePerformanceMetrics, }: InitOptions): void;
6
6
  /**
7
7
  * Connects to an Onyx key given the options passed and listens to its changes.
8
8
  *
@@ -134,7 +134,7 @@ declare function update(data: OnyxUpdate[]): Promise<void>;
134
134
  */
135
135
  declare function setCollection<TKey extends CollectionKeyBase, TMap extends string>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TMap>): Promise<void>;
136
136
  declare const Onyx: {
137
- readonly METHOD: {
137
+ METHOD: {
138
138
  readonly SET: "set";
139
139
  readonly MERGE: "merge";
140
140
  readonly MERGE_COLLECTION: "mergecollection";
@@ -142,17 +142,17 @@ declare const Onyx: {
142
142
  readonly MULTI_SET: "multiset";
143
143
  readonly CLEAR: "clear";
144
144
  };
145
- readonly connect: typeof connect;
146
- readonly disconnect: typeof disconnect;
147
- readonly set: typeof set;
148
- readonly multiSet: typeof multiSet;
149
- readonly merge: typeof merge;
150
- readonly mergeCollection: typeof mergeCollection;
151
- readonly setCollection: typeof setCollection;
152
- readonly update: typeof update;
153
- readonly clear: typeof clear;
154
- readonly init: typeof init;
155
- readonly registerLogger: typeof Logger.registerLogger;
145
+ connect: typeof connect;
146
+ disconnect: typeof disconnect;
147
+ set: typeof set;
148
+ multiSet: typeof multiSet;
149
+ merge: typeof merge;
150
+ mergeCollection: typeof mergeCollection;
151
+ setCollection: typeof setCollection;
152
+ update: typeof update;
153
+ clear: typeof clear;
154
+ init: typeof init;
155
+ registerLogger: typeof Logger.registerLogger;
156
156
  };
157
157
  export default Onyx;
158
158
  export type { OnyxUpdate, Mapping, ConnectOptions };
package/dist/Onyx.js CHANGED
@@ -38,9 +38,15 @@ const DevTools_1 = __importDefault(require("./DevTools"));
38
38
  const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
39
39
  const logMessages_1 = __importDefault(require("./logMessages"));
40
40
  const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager"));
41
+ const GlobalSettings = __importStar(require("./GlobalSettings"));
42
+ const metrics_1 = __importDefault(require("./metrics"));
41
43
  /** Initialize the store with actions and listening for storage events */
42
- function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, }) {
44
+ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, enablePerformanceMetrics = false, }) {
43
45
  var _a;
46
+ if (enablePerformanceMetrics) {
47
+ GlobalSettings.setPerformanceMetricsEnabled(true);
48
+ applyDecorators();
49
+ }
44
50
  storage_1.default.init();
45
51
  if (shouldSyncMultipleInstances) {
46
52
  (_a = storage_1.default.keepInstancesSync) === null || _a === void 0 ? void 0 : _a.call(storage_1.default, (key, value) => {
@@ -672,4 +678,23 @@ const Onyx = {
672
678
  init,
673
679
  registerLogger: Logger.registerLogger,
674
680
  };
681
+ function applyDecorators() {
682
+ // We are reassigning the functions directly so that internal function calls are also decorated
683
+ /* eslint-disable rulesdir/prefer-actions-set-data */
684
+ // @ts-expect-error Reassign
685
+ connect = (0, metrics_1.default)(connect, 'Onyx.connect');
686
+ // @ts-expect-error Reassign
687
+ set = (0, metrics_1.default)(set, 'Onyx.set');
688
+ // @ts-expect-error Reassign
689
+ multiSet = (0, metrics_1.default)(multiSet, 'Onyx.multiSet');
690
+ // @ts-expect-error Reassign
691
+ merge = (0, metrics_1.default)(merge, 'Onyx.merge');
692
+ // @ts-expect-error Reassign
693
+ mergeCollection = (0, metrics_1.default)(mergeCollection, 'Onyx.mergeCollection');
694
+ // @ts-expect-error Reassign
695
+ update = (0, metrics_1.default)(update, 'Onyx.update');
696
+ // @ts-expect-error Reassign
697
+ clear = (0, metrics_1.default)(clear, 'Onyx.clear');
698
+ /* eslint-enable rulesdir/prefer-actions-set-data */
699
+ }
675
700
  exports.default = Onyx;
package/dist/OnyxUtils.js CHANGED
@@ -39,6 +39,8 @@ const batch_1 = __importDefault(require("./batch"));
39
39
  const storage_1 = __importDefault(require("./storage"));
40
40
  const utils_1 = __importDefault(require("./utils"));
41
41
  const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
42
+ const GlobalSettings = __importStar(require("./GlobalSettings"));
43
+ const metrics_1 = __importDefault(require("./metrics"));
42
44
  // Method constants
43
45
  const METHOD = {
44
46
  SET: 'set',
@@ -1161,4 +1163,48 @@ const OnyxUtils = {
1161
1163
  unsubscribeFromKey,
1162
1164
  getEvictionBlocklist,
1163
1165
  };
1166
+ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) => {
1167
+ if (!enablePerformanceMetrics) {
1168
+ return;
1169
+ }
1170
+ // We are reassigning the functions directly so that internal function calls are also decorated
1171
+ // @ts-expect-error Reassign
1172
+ initStoreValues = (0, metrics_1.default)(initStoreValues, 'OnyxUtils.initStoreValues');
1173
+ // @ts-expect-error Reassign
1174
+ maybeFlushBatchUpdates = (0, metrics_1.default)(maybeFlushBatchUpdates, 'OnyxUtils.maybeFlushBatchUpdates');
1175
+ // @ts-expect-error Reassign
1176
+ batchUpdates = (0, metrics_1.default)(batchUpdates, 'OnyxUtils.batchUpdates');
1177
+ // @ts-expect-error Complex type signature
1178
+ get = (0, metrics_1.default)(get, 'OnyxUtils.get');
1179
+ // @ts-expect-error Reassign
1180
+ getAllKeys = (0, metrics_1.default)(getAllKeys, 'OnyxUtils.getAllKeys');
1181
+ // @ts-expect-error Reassign
1182
+ getCollectionKeys = (0, metrics_1.default)(getCollectionKeys, 'OnyxUtils.getCollectionKeys');
1183
+ // @ts-expect-error Reassign
1184
+ addAllSafeEvictionKeysToRecentlyAccessedList = (0, metrics_1.default)(addAllSafeEvictionKeysToRecentlyAccessedList, 'OnyxUtils.addAllSafeEvictionKeysToRecentlyAccessedList');
1185
+ // @ts-expect-error Reassign
1186
+ keysChanged = (0, metrics_1.default)(keysChanged, 'OnyxUtils.keysChanged');
1187
+ // @ts-expect-error Reassign
1188
+ keyChanged = (0, metrics_1.default)(keyChanged, 'OnyxUtils.keyChanged');
1189
+ // @ts-expect-error Reassign
1190
+ sendDataToConnection = (0, metrics_1.default)(sendDataToConnection, 'OnyxUtils.sendDataToConnection');
1191
+ // @ts-expect-error Reassign
1192
+ scheduleSubscriberUpdate = (0, metrics_1.default)(scheduleSubscriberUpdate, 'OnyxUtils.scheduleSubscriberUpdate');
1193
+ // @ts-expect-error Reassign
1194
+ scheduleNotifyCollectionSubscribers = (0, metrics_1.default)(scheduleNotifyCollectionSubscribers, 'OnyxUtils.scheduleNotifyCollectionSubscribers');
1195
+ // @ts-expect-error Reassign
1196
+ remove = (0, metrics_1.default)(remove, 'OnyxUtils.remove');
1197
+ // @ts-expect-error Reassign
1198
+ reportStorageQuota = (0, metrics_1.default)(reportStorageQuota, 'OnyxUtils.reportStorageQuota');
1199
+ // @ts-expect-error Complex type signature
1200
+ evictStorageAndRetry = (0, metrics_1.default)(evictStorageAndRetry, 'OnyxUtils.evictStorageAndRetry');
1201
+ // @ts-expect-error Reassign
1202
+ broadcastUpdate = (0, metrics_1.default)(broadcastUpdate, 'OnyxUtils.broadcastUpdate');
1203
+ // @ts-expect-error Reassign
1204
+ initializeWithDefaultKeyStates = (0, metrics_1.default)(initializeWithDefaultKeyStates, 'OnyxUtils.initializeWithDefaultKeyStates');
1205
+ // @ts-expect-error Complex type signature
1206
+ multiGet = (0, metrics_1.default)(multiGet, 'OnyxUtils.multiGet');
1207
+ // @ts-expect-error Reassign
1208
+ subscribeToKey = (0, metrics_1.default)(subscribeToKey, 'OnyxUtils.subscribeToKey');
1209
+ });
1164
1210
  exports.default = OnyxUtils;
@@ -0,0 +1,10 @@
1
+ type ImportType = ReturnType<typeof require>;
2
+ /**
3
+ * Create a lazily-imported module proxy.
4
+ * This is useful for lazily requiring optional dependencies.
5
+ */
6
+ declare const createModuleProxy: <TModule>(getModule: () => ImportType) => TModule;
7
+ declare class OptionalDependencyNotInstalledError extends Error {
8
+ constructor(name: string);
9
+ }
10
+ export { createModuleProxy, OptionalDependencyNotInstalledError };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OptionalDependencyNotInstalledError = exports.createModuleProxy = void 0;
4
+ /**
5
+ * Create a lazily-imported module proxy.
6
+ * This is useful for lazily requiring optional dependencies.
7
+ */
8
+ const createModuleProxy = (getModule) => {
9
+ const holder = { module: undefined };
10
+ const proxy = new Proxy(holder, {
11
+ get: (target, property) => {
12
+ if (property === '$$typeof') {
13
+ // If inlineRequires is enabled, Metro will look up all imports
14
+ // with the $$typeof operator. In this case, this will throw the
15
+ // `OptionalDependencyNotInstalledError` error because we try to access the module
16
+ // even though we are not using it (Metro does it), so instead we return undefined
17
+ // to bail out of inlineRequires here.
18
+ return undefined;
19
+ }
20
+ if (target.module == null) {
21
+ // lazy initialize module via require()
22
+ // caller needs to make sure the require() call is wrapped in a try/catch
23
+ // eslint-disable-next-line no-param-reassign
24
+ target.module = getModule();
25
+ }
26
+ return target.module[property];
27
+ },
28
+ });
29
+ return proxy;
30
+ };
31
+ exports.createModuleProxy = createModuleProxy;
32
+ class OptionalDependencyNotInstalledError extends Error {
33
+ constructor(name) {
34
+ super(`${name} is not installed!`);
35
+ }
36
+ }
37
+ exports.OptionalDependencyNotInstalledError = OptionalDependencyNotInstalledError;
@@ -0,0 +1 @@
1
+ export default performance;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Use the existing performance API on web
4
+ exports.default = performance;
@@ -0,0 +1,20 @@
1
+ declare const PerformanceProxy: {
2
+ timeOrigin: number;
3
+ now: () => number;
4
+ mark: (markName: string, markOptions?: import("react-native-performance/lib/typescript/performance").MarkOptions | undefined) => import("react-native-performance").PerformanceMark;
5
+ clearMarks: (name?: string | undefined) => void;
6
+ measure: (measureName: string, startOrMeasureOptions?: import("react-native-performance/lib/typescript/performance").StartOrMeasureOptions, endMark?: string | number | undefined) => import("react-native-performance").PerformanceMeasure;
7
+ clearMeasures: (name?: string | undefined) => void;
8
+ metric: (name: string, valueOrOptions: import("react-native-performance/lib/typescript/performance").ValueOrOptions) => import("react-native-performance").PerformanceMetric;
9
+ clearMetrics: (name?: string | undefined) => void;
10
+ getEntries: () => import("react-native-performance").PerformanceEntry[];
11
+ getEntriesByName: (name: string, type?: import("react-native-performance").EntryType | undefined) => import("react-native-performance").PerformanceEntry[];
12
+ getEntriesByType: {
13
+ (type: "measure"): import("react-native-performance").PerformanceMeasure[];
14
+ (type: "mark"): import("react-native-performance").PerformanceMark[];
15
+ (type: "resource"): import("react-native-performance").PerformanceResourceTiming[];
16
+ (type: "metric"): import("react-native-performance").PerformanceMetric[];
17
+ (type: "react-native-mark"): import("react-native-performance").PerformanceReactNativeMark[];
18
+ };
19
+ };
20
+ export default PerformanceProxy;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ModuleProxy_1 = require("../ModuleProxy");
4
+ const PerformanceProxy = (0, ModuleProxy_1.createModuleProxy)(() => {
5
+ try {
6
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
7
+ return require('react-native-performance').default;
8
+ }
9
+ catch (_a) {
10
+ throw new ModuleProxy_1.OptionalDependencyNotInstalledError('react-native-performance');
11
+ }
12
+ });
13
+ exports.default = PerformanceProxy;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Wraps a function with metrics capturing logic
3
+ */
4
+ declare function decorateWithMetrics<Args extends unknown[], ReturnType>(func: (...args: Args) => ReturnType, alias?: string): {
5
+ (...args: Args): ReturnType;
6
+ name: string;
7
+ };
8
+ export default decorateWithMetrics;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const PerformanceProxy_1 = __importDefault(require("./dependencies/PerformanceProxy"));
7
+ const decoratedAliases = new Set();
8
+ /**
9
+ * Capture a measurement between the start mark and now
10
+ */
11
+ function measureMarkToNow(startMark, detail) {
12
+ PerformanceProxy_1.default.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, {
13
+ start: startMark.startTime,
14
+ end: PerformanceProxy_1.default.now(),
15
+ detail: Object.assign(Object.assign({}, startMark.detail), detail),
16
+ });
17
+ }
18
+ function isPromiseLike(value) {
19
+ return value != null && typeof value === 'object' && 'then' in value;
20
+ }
21
+ /**
22
+ * Wraps a function with metrics capturing logic
23
+ */
24
+ function decorateWithMetrics(func, alias = func.name) {
25
+ if (decoratedAliases.has(alias)) {
26
+ throw new Error(`"${alias}" is already decorated`);
27
+ }
28
+ decoratedAliases.add(alias);
29
+ function decorated(...args) {
30
+ const mark = PerformanceProxy_1.default.mark(alias, { detail: { args, alias } });
31
+ const originalReturnValue = func(...args);
32
+ if (isPromiseLike(originalReturnValue)) {
33
+ /*
34
+ * The handlers added here are not affecting the original promise
35
+ * They create a separate chain that's not exposed (returned) to the original caller
36
+ */
37
+ originalReturnValue
38
+ .then((result) => {
39
+ measureMarkToNow(mark, { result });
40
+ })
41
+ .catch((error) => {
42
+ measureMarkToNow(mark, { error });
43
+ });
44
+ return originalReturnValue;
45
+ }
46
+ measureMarkToNow(mark, { result: originalReturnValue });
47
+ return originalReturnValue;
48
+ }
49
+ decorated.name = `${alias}_DECORATED`;
50
+ return decorated;
51
+ }
52
+ exports.default = decorateWithMetrics;
@@ -2,5 +2,5 @@ import type StorageProvider from './providers/types';
2
2
  type Storage = {
3
3
  getStorageProvider: () => StorageProvider;
4
4
  } & Omit<StorageProvider, 'name'>;
5
- declare const Storage: Storage;
6
- export default Storage;
5
+ declare const storage: Storage;
6
+ export default storage;
@@ -30,6 +30,8 @@ const Logger = __importStar(require("../Logger"));
30
30
  const platforms_1 = __importDefault(require("./platforms"));
31
31
  const InstanceSync_1 = __importDefault(require("./InstanceSync"));
32
32
  const MemoryOnlyProvider_1 = __importDefault(require("./providers/MemoryOnlyProvider"));
33
+ const GlobalSettings = __importStar(require("../GlobalSettings"));
34
+ const metrics_1 = __importDefault(require("../metrics"));
33
35
  let provider = platforms_1.default;
34
36
  let shouldKeepInstancesSync = false;
35
37
  let finishInitalization;
@@ -71,7 +73,7 @@ function tryOrDegradePerformance(fn, waitForInitialization = true) {
71
73
  });
72
74
  });
73
75
  }
74
- const Storage = {
76
+ const storage = {
75
77
  /**
76
78
  * Returns the storage provider currently in use
77
79
  */
@@ -184,4 +186,20 @@ const Storage = {
184
186
  InstanceSync_1.default.init(onStorageKeyChanged, this);
185
187
  },
186
188
  };
187
- exports.default = Storage;
189
+ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) => {
190
+ if (!enablePerformanceMetrics) {
191
+ return;
192
+ }
193
+ // Apply decorators
194
+ storage.getItem = (0, metrics_1.default)(storage.getItem, 'Storage.getItem');
195
+ storage.multiGet = (0, metrics_1.default)(storage.multiGet, 'Storage.multiGet');
196
+ storage.setItem = (0, metrics_1.default)(storage.setItem, 'Storage.setItem');
197
+ storage.multiSet = (0, metrics_1.default)(storage.multiSet, 'Storage.multiSet');
198
+ storage.mergeItem = (0, metrics_1.default)(storage.mergeItem, 'Storage.mergeItem');
199
+ storage.multiMerge = (0, metrics_1.default)(storage.multiMerge, 'Storage.multiMerge');
200
+ storage.removeItem = (0, metrics_1.default)(storage.removeItem, 'Storage.removeItem');
201
+ storage.removeItems = (0, metrics_1.default)(storage.removeItems, 'Storage.removeItems');
202
+ storage.clear = (0, metrics_1.default)(storage.clear, 'Storage.clear');
203
+ storage.getAllKeys = (0, metrics_1.default)(storage.getAllKeys, 'Storage.getAllKeys');
204
+ });
205
+ exports.default = storage;
package/dist/types.d.ts CHANGED
@@ -393,6 +393,11 @@ type InitOptions = {
393
393
  shouldSyncMultipleInstances?: boolean;
394
394
  /** Enables debugging setState() calls to connected components */
395
395
  debugSetState?: boolean;
396
+ /**
397
+ * If enabled it will use the performance API to measure the time taken by Onyx operations.
398
+ * @default false
399
+ */
400
+ enablePerformanceMetrics?: boolean;
396
401
  };
397
402
  type GenericFunction = (...args: any[]) => any;
398
403
  /**
package/dist/useOnyx.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { DependencyList } from 'react';
1
2
  import type { OnyxKey, OnyxValue } from './types';
2
3
  type BaseUseOnyxOptions = {
3
4
  /**
@@ -40,7 +41,7 @@ type ResultMetadata = {
40
41
  status: FetchStatus;
41
42
  };
42
43
  type UseOnyxResult<TValue> = [NonNullable<TValue> | undefined, ResultMetadata];
43
- declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & Required<UseOnyxSelectorOption<TKey, TReturnValue>>): UseOnyxResult<TReturnValue>;
44
- declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<NoInfer<TReturnValue>>): UseOnyxResult<TReturnValue>;
44
+ declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & Required<UseOnyxSelectorOption<TKey, TReturnValue>>, dependencies?: DependencyList): UseOnyxResult<TReturnValue>;
45
+ declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<NoInfer<TReturnValue>>, dependencies?: DependencyList): UseOnyxResult<TReturnValue>;
45
46
  export default useOnyx;
46
47
  export type { FetchStatus, ResultMetadata, UseOnyxResult };
package/dist/useOnyx.js CHANGED
@@ -64,7 +64,7 @@ function getCachedValue(key, selector) {
64
64
  const selectedValue = selector ? selector(value) : value;
65
65
  return selectedValue !== null && selectedValue !== void 0 ? selectedValue : undefined;
66
66
  }
67
- function useOnyx(key, options) {
67
+ function useOnyx(key, options, dependencies = []) {
68
68
  const connectionRef = (0, react_1.useRef)(null);
69
69
  const previousKey = (0, usePrevious_1.default)(key);
70
70
  // Used to stabilize the selector reference and avoid unnecessary calls to `getSnapshot()`.
@@ -86,6 +86,10 @@ function useOnyx(key, options) {
86
86
  // Indicates if it's the first Onyx connection of this hook or not, as we don't want certain use cases
87
87
  // in `getSnapshot()` to be satisfied several times.
88
88
  const isFirstConnectionRef = (0, react_1.useRef)(true);
89
+ // Indicates if the hook is connecting to a Onyx key.
90
+ const isConnectingRef = (0, react_1.useRef)(false);
91
+ // Stores the `onStoreChange()` function, which can be used to trigger a `getSnapshot()` update when desired.
92
+ const onStoreChangeFnRef = (0, react_1.useRef)(null);
89
93
  // Indicates if we should get the newest cached value from Onyx during `getSnapshot()` execution.
90
94
  const shouldGetCachedValueRef = (0, react_1.useRef)(true);
91
95
  (0, react_1.useEffect)(() => {
@@ -107,6 +111,17 @@ function useOnyx(key, options) {
107
111
  }
108
112
  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'.`);
109
113
  }, [previousKey, key]);
114
+ (0, react_1.useEffect)(() => {
115
+ // This effect will only run if the `dependencies` array changes. If it changes it will force the hook
116
+ // to trigger a `getSnapshot()` update by calling the stored `onStoreChange()` function reference, thus
117
+ // re-running the hook and returning the latest value to the consumer.
118
+ if (connectionRef.current === null || isConnectingRef.current || !onStoreChangeFnRef.current) {
119
+ return;
120
+ }
121
+ shouldGetCachedValueRef.current = true;
122
+ onStoreChangeFnRef.current();
123
+ // eslint-disable-next-line react-hooks/exhaustive-deps
124
+ }, [...dependencies]);
110
125
  // Mimics withOnyx's checkEvictableKeys() behavior.
111
126
  const checkEvictableKey = (0, react_1.useCallback)(() => {
112
127
  if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionRef.current) {
@@ -182,9 +197,13 @@ function useOnyx(key, options) {
182
197
  return resultRef.current;
183
198
  }, [options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.initialValue, key, selectorRef]);
184
199
  const subscribe = (0, react_1.useCallback)((onStoreChange) => {
200
+ isConnectingRef.current = true;
201
+ onStoreChangeFnRef.current = onStoreChange;
185
202
  connectionRef.current = OnyxConnectionManager_1.default.connect({
186
203
  key,
187
204
  callback: () => {
205
+ isConnectingRef.current = false;
206
+ onStoreChangeFnRef.current = onStoreChange;
188
207
  // Signals that the first connection was made, so some logics in `getSnapshot()`
189
208
  // won't be executed anymore.
190
209
  isFirstConnectionRef.current = false;
@@ -204,6 +223,8 @@ function useOnyx(key, options) {
204
223
  }
205
224
  OnyxConnectionManager_1.default.disconnect(connectionRef.current);
206
225
  isFirstConnectionRef.current = false;
226
+ isConnectingRef.current = false;
227
+ onStoreChangeFnRef.current = null;
207
228
  };
208
229
  }, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.reuseConnection, checkEvictableKey]);
209
230
  (0, react_1.useEffect)(() => {
package/lib/index.ts ADDED
@@ -0,0 +1,51 @@
1
+ import type {ConnectOptions, OnyxUpdate} from './Onyx';
2
+ import Onyx from './Onyx';
3
+ import type {
4
+ CustomTypeOptions,
5
+ KeyValueMapping,
6
+ NullishDeep,
7
+ OnyxCollection,
8
+ OnyxEntry,
9
+ OnyxKey,
10
+ OnyxValue,
11
+ Selector,
12
+ OnyxInputValue,
13
+ OnyxCollectionInputValue,
14
+ OnyxInput,
15
+ OnyxSetInput,
16
+ OnyxMultiSetInput,
17
+ OnyxMergeInput,
18
+ OnyxMergeCollectionInput,
19
+ } from './types';
20
+ import type {FetchStatus, ResultMetadata, UseOnyxResult} from './useOnyx';
21
+ import type {Connection} from './OnyxConnectionManager';
22
+ import useOnyx from './useOnyx';
23
+ import withOnyx from './withOnyx';
24
+ import type {WithOnyxState} from './withOnyx/types';
25
+
26
+ export default Onyx;
27
+ export {useOnyx, withOnyx};
28
+ export type {
29
+ ConnectOptions,
30
+ CustomTypeOptions,
31
+ FetchStatus,
32
+ KeyValueMapping,
33
+ NullishDeep,
34
+ OnyxCollection,
35
+ OnyxEntry,
36
+ OnyxKey,
37
+ OnyxInputValue,
38
+ OnyxCollectionInputValue,
39
+ OnyxInput,
40
+ OnyxSetInput,
41
+ OnyxMultiSetInput,
42
+ OnyxMergeInput,
43
+ OnyxMergeCollectionInput,
44
+ OnyxUpdate,
45
+ OnyxValue,
46
+ ResultMetadata,
47
+ Selector,
48
+ UseOnyxResult,
49
+ WithOnyxState,
50
+ Connection,
51
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.82",
3
+ "version": "2.0.84",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -25,8 +25,7 @@
25
25
  "README.md",
26
26
  "LICENSE.md"
27
27
  ],
28
- "main": "dist/index.js",
29
- "types": "dist/index.d.ts",
28
+ "main": "lib/index.ts",
30
29
  "scripts": {
31
30
  "lint": "eslint .",
32
31
  "typecheck": "tsc --noEmit",