Skip to content

Commit

Permalink
fix: refactor persisting store
Browse files Browse the repository at this point in the history
- persist only changed store
- wakeup manage restore state from init and persist data. init has a priority over persist data.
  • Loading branch information
MatthewPattell committed Jan 25, 2024
1 parent cd84db2 commit 8b20ca6
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 27 deletions.
6 changes: 4 additions & 2 deletions src/deep-merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const isObject = (obj: any) => obj !== null && typeof obj === 'object';
/**
* Custom small deep merge function for restore store state
*/
const deepMerge = (target: any, source: any) => {
const deepMerge = (target: any, source: any): boolean => {
if (!isObject(target) || !isObject(source)) {
return;
return false;
}

for (const key in source) {
Expand All @@ -22,6 +22,8 @@ const deepMerge = (target: any, source: any) => {
target[key] = source[key];
}
}

return true;
};

export default deepMerge;
37 changes: 25 additions & 12 deletions src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
IManagerParams,
IStorage,
IStoreParams,
IStorePersisted,
TAnyStore,
TInitStore,
TStoreDefinition,
Expand Down Expand Up @@ -361,7 +362,7 @@ class Manager {

// restore persisted state
if ('wakeup' in store && Manager.persistedStores.has(storeId)) {
store.wakeup?.({ initState, persistedState });
store.wakeup?.({ initState, persistedState, manager: this });
}

// track changes in persisted store
Expand Down Expand Up @@ -508,6 +509,13 @@ class Manager {
store.libDestroyTimer = setTimeout(() => this.removeStore(store), destroyTime);
}

/**
* Get store state
*/
public getStoreState(store: TAnyStore): Record<string, any> {
return store.toJSON?.() ?? Manager.getObservableProps(store);
}

/**
* Get store's state
*/
Expand All @@ -524,29 +532,34 @@ class Manager {
: this.stores;

for (const [storeId, store] of stores.entries()) {
result[storeId] = store.toJSON?.() ?? Manager.getObservableProps(store);
result[storeId] = this.getStoreState(store);
}

return result;
}

/**
* Get persisted store's data
* Save persisted store state to provided storage
*/
public toPersistedJSON(): Record<string, any> {
const result = {};
public async savePersistedStore(store: IStorePersisted): Promise<boolean> {
if (this.options.shouldDisablePersist || !this.storage) {
return false;
}

for (const storeKey of Manager.persistedStores) {
const store = this.stores.get(storeKey);
try {
this.persistData = {
...this.persistData,
[this.getStoreId(store)]: this.getStoreState(store),
};

if (!store) {
continue;
}
await this.storage?.set(this.persistData);

result[storeKey] = store['toJSON']?.() ?? Manager.getObservableProps(store);
return true;
} catch (e) {
console.error('Failed to persist stores: ', e);
}

return result;
return false;
}

/**
Expand Down
12 changes: 2 additions & 10 deletions src/on-change-listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,14 @@ import type { IStorePersisted } from './types';
* Listen persist store changes
*/
const onChangeListener: IStorePersisted['addOnChangeListener'] = (store, manager) => {
const { shouldDisablePersist } = manager.options;

if (shouldDisablePersist || !manager.storage) {
if (manager.options.shouldDisablePersist || !manager.storage) {
return;
}

return reaction(
() => store.toJSON?.() ?? toJS(store),
() => {
try {
manager.storage?.set(manager.toPersistedJSON())?.catch((e: Error) => {
console.error('Failed to persist stores #1: ', e);
});
} catch (e) {
console.error('Failed to persist stores #2: ', e);
}
void manager.savePersistedStore(store);
},
);
};
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface IManagerParams {
}

export type TWakeup = (state: {
manager: Manager;
initState?: Record<string, any>;
persistedState?: Record<string, any>;
}) => void;
Expand Down
17 changes: 14 additions & 3 deletions src/wakeup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ import type { TStores, TWakeup } from './types';
/**
* Restore persisted store state
*/
function wakeup(this: TStores[string], { persistedState }: Parameters<TWakeup>[0]) {
if (persistedState) {
deepMerge(this, persistedState);
function wakeup(
this: TStores[string],
{ initState, persistedState, manager }: Parameters<TWakeup>[0],
) {
const resState = {};

deepMerge(resState, persistedState);

const shouldSave = initState && deepMerge(resState, initState);

deepMerge(this, resState);

if (shouldSave) {
void manager.savePersistedStore(this);
}
}

Expand Down

0 comments on commit 8b20ca6

Please sign in to comment.