[js函数] storageManager
import _get from 'lodash.get'; import _set from 'lodash.set'; import _debounce from 'lodash.debounce'; import {shallowEqual} from "./shallow-equal"; const IS_STORAGE_INITIALIZED = '$$IS_STORAGE_INITIALIZED$$'; interface PersistConfig { save: (storageName: string, storageData: any) => void; load: (storageName: string) => Promise<any>; } type WatcherFn = (nextValue: any, preValue: any, storage: Storage) => void; interface Watcher { path: string, watcher: WatcherFn, preValue: any } class Storage { private readonly storageName: string; private storageData: Record<string, any>; private watcherList: Watcher[]; private persistConfig: PersistConfig | null; private readonly persistStorageFn: any; constructor(storageName: string) { this.storageName = storageName; this.storageData = {}; this.watcherList = []; // {path, watcher, preValue} this.persistConfig = null; // {save:(storageName,storageData)=>{}, load:(storageName)=>{}} this.persistStorageFn = _debounce(() => { this.persistStorage(); }, 100); setTimeout(() => { this.persistStorageInit(); }, 1); } setPersistConfig(persistConfig: PersistConfig) { this.persistConfig = persistConfig; } initStorageData(storageData: Record<string, any>) { this.storageData = storageData; this.storageData[IS_STORAGE_INITIALIZED] = true; this.notifyWatcher(); } getValue(path: string) { return _get(this.storageData, path); } setValue(path: string, value: any) { _set(this.storageData, path, value); this.notifyWatcher(); this.persistStorageFn() } watch(path: string, watcher: WatcherFn) { if (typeof watcher !== "function") { throw 'watcher must function'; } this.watcherList.push({path, watcher, preValue: undefined}); } unwatch(path: string, watcher: WatcherFn) { this.watcherList = this.watcherList.filter((obj) => { return obj.path !== path && obj.watcher !== watcher; }); } notifyWatcher() { const watcherList = this.watcherList || []; for (let i = 0; i < watcherList.length; i++) { const {path, watcher, preValue} = watcherList[i]; const nextValue = this.getValue(path); if (!shallowEqual(nextValue, preValue)) { watcher(nextValue, preValue, this); watcherList[i].preValue = nextValue; } } } persistStorage() { const persistConfig = this.persistConfig; if (!persistConfig) { return; } const {save} = persistConfig; save(this.storageName, this.storageData); } persistStorageInit() { const persistConfig = this.persistConfig; if (!persistConfig) { this.initStorageData({}); return; } const {load} = persistConfig; load(this.storageName).then((storageData) => { if (storageData && typeof storageData === "object") { this.initStorageData(storageData); } else { this.initStorageData({}); } }, () => { this.initStorageData({}); }); } } class StorageManager { private storageMap: Record<string, Storage> = {}; getStorage(storageName: string) { if (!this.storageMap[storageName]) { this.storageMap[storageName] = new Storage(storageName); } return this.storageMap[storageName]; } } const storageManager = new StorageManager(); export { storageManager, IS_STORAGE_INITIALIZED }
import localforage from '@ali/ascp-shared-local-forage' /** * 使用 localStorage 存储 */ const localStoragePersist = { save: (storageName, storageData) => { localStorage.setItem(storageName, JSON.stringify(storageData)); }, load: (storageName) => { return new Promise((resolve) => { const str = localStorage.getItem(storageName); if (str) { resolve(JSON.parse(str)) } else { resolve(null); } }) } } /** * 使用 localforage 存储 */ const localForagePersist = { save: (storageName, storageData) => { localforage.setItem(storageName, storageData); }, load: (storageName) => { return localforage.getItem(storageName); } }; export { localStoragePersist, localForagePersist }
import {useEffect, useState} from 'react'; import {storageManager} from "../utils/storage"; function useStorageValue(storageName, persistConfig, path) { const storage = storageManager.getStorage(storageName); storage.setPersistConfig(persistConfig) const [value, setValue] = useState(() => { return storage.getValue(path); }); useEffect(() => { const watcher = (nowValue) => { setValue(nowValue); }; storage.watch(path, watcher); return () => { storage.unwatch(path, watcher); } }, [storageName, path]); return value; } export { useStorageValue }