mirror of https://github.com/msgbyte/tailchat
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.1 KiB
TypeScript
86 lines
2.1 KiB
TypeScript
/* eslint-disable no-empty */
|
|
import { useState } from 'react';
|
|
import { useMemoizedFn } from '../useMemoizedFn';
|
|
import { useUpdateEffect } from '../useUpdateEffect';
|
|
import _isFunction from 'lodash/isFunction';
|
|
import _isUndefined from 'lodash/isUndefined';
|
|
|
|
export interface IFuncUpdater<T> {
|
|
(previousState?: T): T;
|
|
}
|
|
export interface IFuncStorage {
|
|
(): Storage;
|
|
}
|
|
|
|
export interface Options<T> {
|
|
serializer?: (value: T) => string;
|
|
deserializer?: (value: string) => T;
|
|
defaultValue?: T | IFuncUpdater<T>;
|
|
}
|
|
|
|
export function createUseStorageState(getStorage: () => Storage | undefined) {
|
|
function useStorageState<T>(key: string, options?: Options<T>) {
|
|
let storage: Storage | undefined;
|
|
|
|
// https://github.com/alibaba/hooks/issues/800
|
|
try {
|
|
storage = getStorage();
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
|
|
const serializer = (value: T) => {
|
|
if (options?.serializer) {
|
|
return options?.serializer(value);
|
|
}
|
|
return JSON.stringify(value);
|
|
};
|
|
|
|
const deserializer = (value: string) => {
|
|
if (options?.deserializer) {
|
|
return options?.deserializer(value);
|
|
}
|
|
return JSON.parse(value);
|
|
};
|
|
|
|
function getStoredValue() {
|
|
try {
|
|
const raw = storage?.getItem(key);
|
|
if (raw) {
|
|
return deserializer(raw);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
if (_isFunction(options?.defaultValue)) {
|
|
return options?.defaultValue();
|
|
}
|
|
return options?.defaultValue;
|
|
}
|
|
|
|
const [state, setState] = useState<T>(() => getStoredValue());
|
|
|
|
useUpdateEffect(() => {
|
|
setState(getStoredValue());
|
|
}, [key]);
|
|
|
|
const updateState = (value: T | IFuncUpdater<T>) => {
|
|
const currentState = _isFunction(value) ? value(state) : value;
|
|
setState(currentState);
|
|
|
|
if (_isUndefined(currentState)) {
|
|
storage?.removeItem(key);
|
|
} else {
|
|
try {
|
|
storage?.setItem(key, serializer(currentState));
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
};
|
|
|
|
return [state, useMemoizedFn(updateState)] as const;
|
|
}
|
|
return useStorageState;
|
|
}
|