优化
This commit is contained in:
26
client/shared/hooks/factory/createUpdateEffect.ts
Normal file
26
client/shared/hooks/factory/createUpdateEffect.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useRef } from 'react';
|
||||
import type { useEffect, useLayoutEffect } from 'react';
|
||||
|
||||
// Reference: https://github.com/alibaba/hooks/blob/master/packages/hooks/src/createUpdateEffect/index.ts
|
||||
|
||||
type EffectHookType = typeof useEffect | typeof useLayoutEffect;
|
||||
|
||||
export const createUpdateEffect: (hook: EffectHookType) => EffectHookType =
|
||||
(hook) => (effect, deps) => {
|
||||
const isMounted = useRef(false);
|
||||
|
||||
// for react-refresh
|
||||
hook(() => {
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
hook(() => {
|
||||
if (!isMounted.current) {
|
||||
isMounted.current = true;
|
||||
} else {
|
||||
return effect();
|
||||
}
|
||||
}, deps);
|
||||
};
|
||||
85
client/shared/hooks/factory/createUseStorageState.ts
Normal file
85
client/shared/hooks/factory/createUseStorageState.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user