import type { Reducer, Store, Unsubscribe } from 'redux'; import { actionHydrate, isHydrateAction } from '../actions/persist'; import { freezeState } from '../utils/freezeState'; import { PersistItem, PersistOptions } from './PersistItem'; export class PersistManager { protected initialized: boolean = false; protected readonly list: PersistItem[]; protected timer?: ReturnType<typeof setTimeout>; protected unsubscrbeStore!: Unsubscribe; constructor(options: PersistOptions[]) { this.list = options.map((option) => new PersistItem(option)); } init(store: Store, hydrate: boolean) { this.unsubscrbeStore = store.subscribe(() => { this.initialized && this.update(store); }); return Promise.all(this.list.map((item) => item.init())).then(() => { hydrate && store.dispatch(actionHydrate(this.collect())); this.initialized = true; }); } destroy() { this.unsubscrbeStore(); this.initialized = false; } collect(): Record<string, object> { return this.list.reduce<Record<string, object>>((stateMaps, item) => { return Object.assign(stateMaps, item.collect()); }, {}); } combineReducer(original: Reducer): Reducer<Record<string, object>> { return (state, action) => { if (state === void 0) state = {}; if (isHydrateAction(action)) { return Object.assign({}, state, freezeState(action.payload)); } return original(state, action); }; } protected update(store: Store) { this.timer ||= setTimeout(() => { const nextState = store.getState(); this.timer = void 0; for (let i = this.list.length; i-- > 0; ) { this.list[i]!.update(nextState); } }, 50); } }