rc-localforage
Version:
rc-localforage 是 localForage 在 React 的封装包,它提供了一种更符合 React 的使用风格(functional component style),同时保持了 localForage 的大部分功能
117 lines (103 loc) • 3.31 kB
text/typescript
import { useState, useEffect, useContext } from 'react';
import localForage from 'localforage';
import { LocalForageContext } from './LocalForageProvider';
import clientCache from './ClientCache';
import { ExtraOptions } from './type';
import { isBrowser } from './utils';
export function useLocalForage<TState = any>(key: string, options?: ExtraOptions<TState>) {
const { defaultValue, target } = options ?? {};
// determine whether it is a browser environment, if not, return the default value
if (!isBrowser) {
return { value: defaultValue, set: () => {}, remove: () => {}, loading: true };
}
const { config, initialValues } = useContext(LocalForageContext);
// If defaultValue is set, it will override the initial value of the Provider
const globalKeyValue = initialValues?.[key];
const [value, setValue] = useState<TState>(defaultValue ?? globalKeyValue);
const [loading, setLoading] = useState<boolean>(true);
const set = (val: TState) => {
const client = getClient(config, target);
client
.setItem(key, val)
.then(() => {
return client.getItem(key);
})
.then((val: TState) => {
setValue(val);
setLoading(false);
})
.catch((err) => {
setLoading(false);
if (!!options?.errorSetHandler) {
options.errorSetHandler(err);
} else {
console.error(err);
}
});
};
// initialize the value
useEffect(() => {
const client = getClient(config, target);
setLoading(true);
client
.getItem<TState>(key)
.then((val: any) => {
if (val !== null) {
setValue(val);
setLoading(false);
} else {
set(value);
}
})
.catch((err) => {
setLoading(false);
if (!!options?.errorGetHandler) {
options.errorGetHandler(err);
} else {
console.error(err);
}
});
}, []);
useEffect(() => {
let configKey = target ? JSON.stringify(target) : JSON.stringify(config);
const handleStorageChange = () => {
if (!clientCache.hasCache(configKey)) {
setValue(undefined!);
return;
}
clientCache
.getCache(configKey)
?.length()
.then((length) => {
if (length === 0) {
setValue(undefined!);
}
});
};
clientCache.addEventListener('change', handleStorageChange);
return () => {
clientCache.removeEventListener('change', handleStorageChange);
};
}, []);
const remove = () => {
const client = getClient(config, target);
client.removeItem(key).then(() => {
setValue(undefined!);
});
};
return { value, set, remove, loading };
}
function getClient(config: LocalForageOptions, target?: LocalForageOptions) {
let cache: LocalForage = localForage;
let configString = JSON.stringify(config);
if (!clientCache.hasCache(configString)) {
clientCache.addCache(configString, localForage.createInstance(config));
}
let targetString = JSON.stringify(target);
if (!!targetString && clientCache.hasCache(targetString)) {
cache = clientCache.getCache(targetString) as LocalForage;
} else {
cache = clientCache.getCache(configString) as LocalForage;
}
return cache;
}