Allow onExport handler to return nothing
Summary: In many cases, the onExport handler doesn't try to customise the format, but merely fetch some additional information before creating an export. By allowing the `onExport` handler to also return nothing, and instead merely update existing state, this case will be easier to express now; Reviewed By: nikoant Differential Revision: D28026558 fbshipit-source-id: 2b90b3e1ced6a6a5b42938b6f6b74b0eb9ceafc0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c2a07e7638
commit
d26ea5fa46
@@ -357,8 +357,7 @@ test('plugins can handle import errors', async () => {
|
||||
});
|
||||
|
||||
test('plugins can have custom export handler', async () => {
|
||||
const {exportStateAsync} = TestUtils.startPlugin(
|
||||
{
|
||||
const {exportStateAsync} = TestUtils.startPlugin({
|
||||
plugin(client: PluginClient) {
|
||||
const field1 = createState(0, {persist: 'field1'});
|
||||
|
||||
@@ -374,15 +373,34 @@ test('plugins can have custom export handler', async () => {
|
||||
Component() {
|
||||
return null;
|
||||
},
|
||||
});
|
||||
expect(await exportStateAsync()).toEqual({b: 3});
|
||||
});
|
||||
|
||||
test('plugins can have custom export handler that doesnt return', async () => {
|
||||
const {exportStateAsync} = TestUtils.startPlugin(
|
||||
{
|
||||
plugin(client: PluginClient) {
|
||||
const field1 = createState(0, {persist: 'field1'});
|
||||
|
||||
client.onExport(async () => {
|
||||
await sleep(10);
|
||||
field1.set(field1.get() + 1);
|
||||
});
|
||||
|
||||
return {field1};
|
||||
},
|
||||
Component() {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
{
|
||||
initialState: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
field1: 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(await exportStateAsync()).toEqual({b: 3});
|
||||
expect(await exportStateAsync()).toEqual({field1: 2});
|
||||
});
|
||||
|
||||
test('plugins can receive deeplinks', async () => {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {Logger} from '../utils/Logger';
|
||||
type StateExportHandler<T = any> = (
|
||||
idler: Idler,
|
||||
onStatusMessage: (msg: string) => void,
|
||||
) => Promise<T>;
|
||||
) => Promise<T | undefined | void>;
|
||||
type StateImportHandler<T = any> = (data: T) => void;
|
||||
|
||||
export interface BasePluginClient {
|
||||
@@ -54,8 +54,11 @@ export interface BasePluginClient {
|
||||
/**
|
||||
* Triggered when the current plugin is being exported and should create a snapshot of the state exported.
|
||||
* Overrides the default export behavior and ignores any 'persist' flags of state.
|
||||
*
|
||||
* If an object is returned from the handler, that will be taken as export.
|
||||
* Otherwise, if nothing is returned, the handler will be run, and after the handler has finished the `persist` keys of the different states will be used as export basis.
|
||||
*/
|
||||
onExport<T = any>(exporter: StateExportHandler<T>): void;
|
||||
onExport<T extends object>(exporter: StateExportHandler<T>): void;
|
||||
|
||||
/**
|
||||
* Triggered directly after the plugin instance was created, if the plugin is being restored from a snapshot.
|
||||
@@ -350,6 +353,10 @@ export abstract class BasePluginInstance {
|
||||
'Cannot export sync a plugin that does have an export handler',
|
||||
);
|
||||
}
|
||||
return this.serializeRootStates();
|
||||
}
|
||||
|
||||
private serializeRootStates() {
|
||||
return Object.fromEntries(
|
||||
Object.entries(this.rootStates).map(([key, atom]) => [
|
||||
key,
|
||||
@@ -363,9 +370,13 @@ export abstract class BasePluginInstance {
|
||||
onStatusMessage: (msg: string) => void,
|
||||
): Promise<Record<string, any>> {
|
||||
if (this.exportHandler) {
|
||||
return await this.exportHandler(idler, onStatusMessage);
|
||||
const result = await this.exportHandler(idler, onStatusMessage);
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
return this.exportStateSync();
|
||||
// intentional fall-through, the export handler merely updated the state, but prefers the default export format
|
||||
}
|
||||
return this.serializeRootStates();
|
||||
}
|
||||
|
||||
isPersistable(): boolean {
|
||||
|
||||
@@ -149,11 +149,13 @@ Trigger when the users navigates to this plugin using a deeplink, either from an
|
||||
|
||||
Usage: `client.onExport(callback: (idler, onStatusMessage) => Promise<state>)`
|
||||
|
||||
Overrides the default serialization behavior of this plugin. Should return a promise with persistable state that is to be stored.
|
||||
Overrides the default serialization behavior of this plugin. Should return a promise with persistable state that is to be stored, or nothing at all.
|
||||
This process is async, so it is possible to first fetch some additional state from the device.
|
||||
|
||||
Serializable is defined as: non-cyclic data, consisting purely of primitive values, plain objects, arrays or Date, Set or Map objects.
|
||||
|
||||
If nothing is returned, the handler will be run, and after the handler has finished the `persist` keys of the different states will be used as export basis.
|
||||
|
||||
#### `onImport`
|
||||
|
||||
Usage: `client.onImport(callback: (snapshot) => void)`
|
||||
|
||||
Reference in New Issue
Block a user