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
}

  

最新文章

  1. 纪念逝去的岁月——C/C++字符串旋转
  2. Powershell获取WMI设备清单
  3. python 练习 2
  4. GC学习笔记
  5. MFC六大核心机制之二:运行时类型识别(RTTI)
  6. C语言break语句
  7. 键盘皇者 RealForce 104Pro独家评测
  8. 4个小时实现一个HTML5音乐播放器
  9. 微信小程序开发之详解生命周期方法
  10. JAVA中文件与Byte数组相互转换的方法
  11. phpmyadmin创建mysql的存储过程
  12. C# 基础知识之 Unix 时间戳转换
  13. Java工具之上传文件
  14. LeetCode(65):有效数字
  15. 35.Spring-jdbc支持.md
  16. Oracle查询表主键、外键
  17. POJ 3251 Big Square
  18. 自定义django的admin后台action
  19. Modbus tcp 格式说明 通讯机制 附C#测试工具用于学习,测试
  20. Perf -- Linux下的系统性能调优工具,第 1 部分

热门文章

  1. LG P4148 简单题
  2. JZOJ 3234. 阴阳
  3. 与时俱进的治疗策略不断提高RA无药缓解机会[EULAR2015_SAT0058]
  4. js替换字符中指定所有字符
  5. PostgreSQL函数如何返回数据集
  6. go语言环境配置(windous)
  7. Classical Cipher
  8. vue打印图片
  9. nodejs 后台运行 forever
  10. vue框架回顾