[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
}

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章