Skip to content
40 changes: 0 additions & 40 deletions API-INTERNAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,6 @@ run out of storage the least recently accessed key can be removed.</p>
<dt><a href="#getCollectionDataAndSendAsObject">getCollectionDataAndSendAsObject()</a></dt>
<dd><p>Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.</p>
</dd>
<dt><a href="#prepareSubscriberUpdate">prepareSubscriberUpdate(callback)</a></dt>
<dd><p>Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.</p>
</dd>
<dt><a href="#scheduleSubscriberUpdate">scheduleSubscriberUpdate()</a></dt>
<dd><p>Schedules an update that will be appended to the macro task queue (so it doesn&#39;t update the subscribers immediately).</p>
</dd>
<dt><a href="#scheduleNotifyCollectionSubscribers">scheduleNotifyCollectionSubscribers()</a></dt>
<dd><p>This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
subscriber callbacks receive the data in a different format than they normally expect and it breaks code.</p>
</dd>
<dt><a href="#remove">remove()</a></dt>
<dd><p>Remove a key from Onyx and update the subscribers</p>
</dd>
Expand Down Expand Up @@ -350,35 +339,6 @@ run out of storage the least recently accessed key can be removed.
## getCollectionDataAndSendAsObject()
Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.

**Kind**: global function
<a name="prepareSubscriberUpdate"></a>

## prepareSubscriberUpdate(callback)
Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.

**Kind**: global function

| Param | Description |
| --- | --- |
| callback | The keyChanged/keysChanged callback |

<a name="scheduleSubscriberUpdate"></a>

## scheduleSubscriberUpdate()
Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).

**Kind**: global function
**Example**
```js
scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
```
<a name="scheduleNotifyCollectionSubscribers"></a>

## scheduleNotifyCollectionSubscribers()
This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
subscriber callbacks receive the data in a different format than they normally expect and it breaks code.

**Kind**: global function
<a name="remove"></a>

Expand Down
22 changes: 9 additions & 13 deletions lib/Onyx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,8 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
return Promise.resolve();
}

return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue, updatePromise}) => {
return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue}) => {
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MERGE, key, changes, mergedValue);
return updatePromise;
});
} catch (error) {
Logger.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
Expand Down Expand Up @@ -376,16 +375,6 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
keysToBeClearedFromStorage.push(key);
}

const updatePromises: Array<Promise<void>> = [];

// Notify the subscribers for each key/value group so they can receive the new values
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
updatePromises.push(OnyxUtils.scheduleSubscriberUpdate(key, value));
}
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
updatePromises.push(OnyxUtils.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
}

// Exclude RAM-only keys to prevent them from being saved to storage
const defaultKeyValuePairs = Object.entries(
Object.keys(defaultKeyStates)
Expand All @@ -404,7 +393,14 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
.then(() => Storage.multiSet(defaultKeyValuePairs))
.then(() => {
DevTools.clearState(keysToPreserve);
return Promise.all(updatePromises);

// Notify the subscribers for each key/value group so they can receive the new values
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
OnyxUtils.keyChanged(key, value);
}
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
OnyxUtils.keysChanged(key, value.newValues, value.oldValues);
}
});
})
.then(() => undefined);
Expand Down
5 changes: 2 additions & 3 deletions lib/OnyxMerge/index.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,20 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);

// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
const updatePromise = OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);
OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);

const shouldSkipStorageOperations = !hasChanged || OnyxKeys.isRamOnlyKey(key);

// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
if (shouldSkipStorageOperations) {
return Promise.resolve({mergedValue, updatePromise});
return Promise.resolve({mergedValue});
}

// For native platforms we use `mergeItem` that will take advantage of JSON_PATCH and JSON_REPLACE SQL operations to
// merge the object in a performant way.
return Storage.mergeItem(key, batchedChanges as OnyxValue<TKey>, replaceNullPatches).then(() => ({
mergedValue,
updatePromise,
}));
};

Expand Down
5 changes: 2 additions & 3 deletions lib/OnyxMerge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);

// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
const updatePromise = OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);
OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);

const shouldSkipStorageOperations = !hasChanged || OnyxKeys.isRamOnlyKey(key);

// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
if (shouldSkipStorageOperations) {
return Promise.resolve({mergedValue, updatePromise});
return Promise.resolve({mergedValue});
}

// For web platforms we use `setItem` since the object was already merged with its changes before.
return Storage.setItem(key, mergedValue as OnyxValue<TKey>).then(() => ({
mergedValue,
updatePromise,
}));
};

Expand Down
1 change: 0 additions & 1 deletion lib/OnyxMerge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {OnyxInput, OnyxKey} from '../types';

type ApplyMergeResult<TValue> = {
mergedValue: TValue;
updatePromise: Promise<void>;
};

type ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | null>(
Expand Down
Loading
Loading