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,6 +357,27 @@ test('plugins can handle import errors', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('plugins can have custom export handler', async () => {
|
test('plugins can have custom export handler', async () => {
|
||||||
|
const {exportStateAsync} = TestUtils.startPlugin({
|
||||||
|
plugin(client: PluginClient) {
|
||||||
|
const field1 = createState(0, {persist: 'field1'});
|
||||||
|
|
||||||
|
client.onExport(async () => {
|
||||||
|
await sleep(10);
|
||||||
|
return {
|
||||||
|
b: 3,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {field1};
|
||||||
|
},
|
||||||
|
Component() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(await exportStateAsync()).toEqual({b: 3});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('plugins can have custom export handler that doesnt return', async () => {
|
||||||
const {exportStateAsync} = TestUtils.startPlugin(
|
const {exportStateAsync} = TestUtils.startPlugin(
|
||||||
{
|
{
|
||||||
plugin(client: PluginClient) {
|
plugin(client: PluginClient) {
|
||||||
@@ -364,9 +385,7 @@ test('plugins can have custom export handler', async () => {
|
|||||||
|
|
||||||
client.onExport(async () => {
|
client.onExport(async () => {
|
||||||
await sleep(10);
|
await sleep(10);
|
||||||
return {
|
field1.set(field1.get() + 1);
|
||||||
b: 3,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {field1};
|
return {field1};
|
||||||
@@ -377,12 +396,11 @@ test('plugins can have custom export handler', async () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
initialState: {
|
initialState: {
|
||||||
a: 1,
|
field1: 1,
|
||||||
b: 2,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expect(await exportStateAsync()).toEqual({b: 3});
|
expect(await exportStateAsync()).toEqual({field1: 2});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('plugins can receive deeplinks', async () => {
|
test('plugins can receive deeplinks', async () => {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {Logger} from '../utils/Logger';
|
|||||||
type StateExportHandler<T = any> = (
|
type StateExportHandler<T = any> = (
|
||||||
idler: Idler,
|
idler: Idler,
|
||||||
onStatusMessage: (msg: string) => void,
|
onStatusMessage: (msg: string) => void,
|
||||||
) => Promise<T>;
|
) => Promise<T | undefined | void>;
|
||||||
type StateImportHandler<T = any> = (data: T) => void;
|
type StateImportHandler<T = any> = (data: T) => void;
|
||||||
|
|
||||||
export interface BasePluginClient {
|
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.
|
* 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.
|
* 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.
|
* 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',
|
'Cannot export sync a plugin that does have an export handler',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return this.serializeRootStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private serializeRootStates() {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(this.rootStates).map(([key, atom]) => [
|
Object.entries(this.rootStates).map(([key, atom]) => [
|
||||||
key,
|
key,
|
||||||
@@ -363,9 +370,13 @@ export abstract class BasePluginInstance {
|
|||||||
onStatusMessage: (msg: string) => void,
|
onStatusMessage: (msg: string) => void,
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, any>> {
|
||||||
if (this.exportHandler) {
|
if (this.exportHandler) {
|
||||||
return await this.exportHandler(idler, onStatusMessage);
|
const result = await this.exportHandler(idler, onStatusMessage);
|
||||||
|
if (result !== undefined) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// intentional fall-through, the export handler merely updated the state, but prefers the default export format
|
||||||
}
|
}
|
||||||
return this.exportStateSync();
|
return this.serializeRootStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
isPersistable(): boolean {
|
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>)`
|
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.
|
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.
|
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`
|
#### `onImport`
|
||||||
|
|
||||||
Usage: `client.onImport(callback: (snapshot) => void)`
|
Usage: `client.onImport(callback: (snapshot) => void)`
|
||||||
|
|||||||
Reference in New Issue
Block a user