Files
testing-tool/src/utils/useStorageState.ts
T
rsgltzyd 17a4dbd8a7 refactor: 优化 RouterProvider 组件的数据加载逻辑
- 使用批量获取方法 `getMany` 替代多个单独的 `get` 调用,简化数据加载过程。
- 更新 `loadInitialData` 函数,确保从存储中获取的默认值更为一致。
- 修改测试用例以验证批量获取的功能,确保组件在不同情况下的正确性。
2026-06-30 22:56:31 +08:00

92 lines
2.5 KiB
TypeScript

import {
useCallback,
useEffect,
useRef,
useState,
type Dispatch,
type SetStateAction,
} from 'react';
import { storageUtil } from '@/utils/chromeStorage';
import { getSyncSnapshot, hasSyncSnapshot } from '@/utils/syncSnapshot';
import type { StorageSchema } from '@/types/storage';
export const useStorageState = <K extends keyof StorageSchema>(
key: K,
defaultValue: StorageSchema[K],
validator?: (val: unknown) => val is StorageSchema[K],
) => {
const [value, setValueInternal] = useState<StorageSchema[K]>(() =>
getSyncSnapshot(key as string, defaultValue, validator),
);
const [isInitialized, setIsInitialized] = useState(false);
const hasLoadedFromStorage = useRef(false);
const loadSucceededRef = useRef(false);
const userModifiedRef = useRef(false);
const setValue = useCallback<Dispatch<SetStateAction<StorageSchema[K]>>>((next) => {
userModifiedRef.current = true;
setValueInternal(next);
}, []);
useEffect(() => {
if (hasLoadedFromStorage.current) return;
let cancelled = false;
const loadState = async () => {
if (hasSyncSnapshot(key as string)) {
if (!cancelled) {
setIsInitialized(true);
hasLoadedFromStorage.current = true;
}
return;
}
try {
const savedValue = await storageUtil.get(key, defaultValue);
if (cancelled) return;
loadSucceededRef.current = true;
if (savedValue !== undefined) {
if (validator) {
setValueInternal(validator(savedValue) ? savedValue : defaultValue);
} else {
setValueInternal(savedValue);
}
}
} catch (error) {
console.error(`加载状态失败 (${key}):`, error);
loadSucceededRef.current = false;
} finally {
if (!cancelled) {
setIsInitialized(true);
hasLoadedFromStorage.current = true;
}
}
};
loadState().catch(console.error);
return () => {
cancelled = true;
};
}, [defaultValue, key, validator]);
useEffect(() => {
if (!isInitialized) return;
if (!loadSucceededRef.current && !userModifiedRef.current) return;
const saveState = async () => {
try {
await storageUtil.set(key, value);
localStorage.setItem(`snapshot/${key}`, JSON.stringify(value));
} catch (error) {
console.error(`保存状态失败 (${key}):`, error);
}
};
saveState().catch(console.error);
}, [value, isInitialized, key]);
return [value, setValue, isInitialized] as const;
};