This commit is contained in:
2026-04-25 16:36:34 +08:00
commit db90e7579b
1876 changed files with 189777 additions and 0 deletions

View 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);
};

View 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;
}