1.4.0 • Published 4 months ago

gpl-async-storage v1.4.0

Weekly downloads
-
License
MulanPSL-2.0
Repository
github
Last release
4 months ago

async-storage

介绍

一个异步 API 的本地存储库

安装

npm i gpl-async-storage

使用

import {
  createAsyncStorage,
  EIndexedDB,
  ELocalStorage,
  ECookie,
} from "gpl-async-storage";

const LS = createAsyncStorage(
  {
    counter: 0,
  },
  // 存储引擎会按照顺序依次尝试,直到找到一个可用存储引擎
  // 这里使用了三个存储引擎,优先级依次为:IndexedDB > localStorage > cookie
  [EIndexedDB(), ELocalStorage(), ECookie()]
);

async function getCounter() {
  // 如果存储引擎为异步,则有可能需要等待存储引擎的初始化完成
  await LS.onReady();

  // 获取数据
  const value1 = await LS.get("counter"); // 0
  return value1;
}

async function setCounter() {
  // 如果存储引擎为异步,则有可能需要等待存储引擎的初始化完成
  await LS.onReady();

  // 设置数据
  await LS.set("counter", 2);

  // 获取数据
  const value2 = await LS.get("counter"); // 2
}

async function setCounter() {
  // 如果存储引擎为异步,则有可能需要等待存储引擎的初始化完成
  await LS.onReady();

  // 删除数据
  await LS.remove("counter");
}

LS.onReady().then(()=>{
  // 订阅 counter 数据变更
  LS.subscribe(async () => {
    const counter = await LS.get("counter");
    console.log("subscribe counter:", counter);
  }, ["counter"]);
});

加密

注意:从 v1.3.0 开始,不再内置加密模块,需要自行引入

import { createAsyncStorage, EIndexedDB } from "gpl-async-storage";
import { AES, enc } from "crypto-js";

function AESEncrypt(message: string, key: string) {
  return AES.encrypt(message, key).toString();
}
function AESDecrypt(message: string, key: string) {
  return AES.decrypt(message, key).toString(enc.Utf8);
}

const LS = createAsyncStorage(
  {
    counter: 0,
  },
  [EIndexedDB()],
  {
    // 加密密钥,有值则会加密存储
    secretKey: "secret",
    EncryptFn: AESEncrypt,
    DecryptFn: AESDecrypt,

    // 所有 key 使用MD5值
    enableHashKey: true,
  }
);

自定义存储引擎

自定义存储引擎需要实现 StorageEngine 接口

export interface StorageEngine<IsAsync extends boolean = true> {
  /** 配置是否支持对象存储,如果为 true 则 setItem 的 value 值可能是 JSON,否则为字符串存储 */
  supportObject?: boolean;
  setItem: (
    key: string,
    value: any
  ) => IsAsync extends true ? Promise<void> : void;
  getItem: (
    key: string
  ) => IsAsync extends true
    ? Promise<any | null | undefined>
    : any | null | undefined;
  removeItem: (key: string) => IsAsync extends true ? Promise<void> : void;
  onReady?: () => Promise<void>;
}

例如:ELocalStorage 的实现如下

import type { StorageEngine } from "gpl-async-storage";

export function ELocalStorage(name = "LS") {
  let ready = false;
  try {
    const testString = "test";
    localStorage.setItem(testString, testString);
    const test = localStorage.getItem(testString);
    if (test === testString) {
      ready = true;
    }
  } catch (error) {
    CusLog.error("ELocalStorage", "unready", error);
  }

  if (!ready) {
    return null;
  }

  const storageEngine: StorageEngine<false> = {
    getItem(key) {
      return localStorage.getItem(`${name}_${key}`);
    },
    setItem(key, value) {
      return localStorage.setItem(`${name}_${key}`, value);
    },
    removeItem(key) {
      return localStorage.removeItem(`${name}_${key}`);
    },
  };

  return storageEngine;
}

由于浏览器的 localStorage (Storage) API 天然符合 StorageEngine 接口,所以在不考虑兼容性的情况下,可以直接使用 localStorage 作为存储引擎。如下:

import { createAsyncStorage } from "gpl-async-storage";

const LS = createAsyncStorage(
  {
    counter: 0,
  },
  [localStorage]
);

react-native

在 react-native 中可直接使用 @react-native-async-storage/async-storage 库作为存储引擎。

import AsyncStorage from "@react-native-async-storage/async-storage";
import { createAsyncStorage } from "gpl-async-storage";
import {useEffect, useState} from 'react';

const initialData = {
  counter: 0,
}

export const LS = createAsyncStorage(
  initialData,
  [AsyncStorage]
);

// 封装 react hooks 可实现使用 LS.set 更新数据时,hook 值实时更新
export function useAsyncStorage<K extends keyof typeof initialData>(key: K) {
  const [state, setState] = useState(initialData[key]);

  useEffect(() => {
    return LS.subscribe(async () => {
      await LS.onReady();
      const value = await LS.get(key);
      setState(value);
    }, [key]);
  }, [key]);

  return state;
}
1.4.0

4 months ago

1.3.1

4 months ago

1.2.5

4 months ago

1.2.4

4 months ago

1.2.3

4 months ago

1.2.2

4 months ago

1.3.0

4 months ago

1.2.0

4 months ago

1.2.1

4 months ago

1.1.1

4 months ago

1.1.0

4 months ago

1.0.1

4 months ago

1.0.0

4 months ago