refactor: 优化 RouterProvider 组件的数据加载逻辑
- 使用批量获取方法 `getMany` 替代多个单独的 `get` 调用,简化数据加载过程。 - 更新 `loadInitialData` 函数,确保从存储中获取的默认值更为一致。 - 修改测试用例以验证批量获取的功能,确保组件在不同情况下的正确性。
This commit is contained in:
@@ -110,13 +110,19 @@ export function RouterProvider({
|
|||||||
|
|
||||||
const loadInitialData = useCallback(async () => {
|
const loadInitialData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const savedRoute = await storageUtil.get(syncKey, defaultRoute);
|
const stored = await storageUtil.getMany([
|
||||||
const savedVisiblePages = await storageUtil.get(
|
syncKey,
|
||||||
visiblePagesKey,
|
visiblePagesKey,
|
||||||
getDefaultVisibleFeatureKeys(),
|
pageOrderKey,
|
||||||
);
|
'app/recentlyUsedTools',
|
||||||
const savedPageOrder = await storageUtil.get(pageOrderKey, getDefaultPageOrder());
|
'contextMenu/pendingData',
|
||||||
const savedRecentTools = await storageUtil.get('app/recentlyUsedTools', []);
|
]);
|
||||||
|
|
||||||
|
const savedRoute = (stored[syncKey] ?? defaultRoute) as PageType;
|
||||||
|
const savedVisiblePages = (stored[visiblePagesKey] ??
|
||||||
|
getDefaultVisibleFeatureKeys()) as PageType[];
|
||||||
|
const savedPageOrder = (stored[pageOrderKey] ?? getDefaultPageOrder()) as PageType[];
|
||||||
|
const savedRecentTools = (stored['app/recentlyUsedTools'] ?? []) as PageType[];
|
||||||
|
|
||||||
if (isValidPage(savedRoute) && syncRoute && !hasUserNavigatedRef.current) {
|
if (isValidPage(savedRoute) && syncRoute && !hasUserNavigatedRef.current) {
|
||||||
setCurrentPage(savedRoute);
|
setCurrentPage(savedRoute);
|
||||||
@@ -131,8 +137,11 @@ export function RouterProvider({
|
|||||||
setRecentlyUsedTools(savedRecentTools);
|
setRecentlyUsedTools(savedRecentTools);
|
||||||
}
|
}
|
||||||
canPersistRef.current = true;
|
canPersistRef.current = true;
|
||||||
|
|
||||||
|
return stored['contextMenu/pendingData'];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Router Init Error] Core data fetch failed:', error);
|
console.error('[Router Init Error] Core data fetch failed:', error);
|
||||||
|
return undefined;
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
}
|
}
|
||||||
@@ -143,7 +152,7 @@ export function RouterProvider({
|
|||||||
|
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- Valid async data loading pattern on mount
|
// eslint-disable-next-line react-hooks/set-state-in-effect -- Valid async data loading pattern on mount
|
||||||
loadInitialData()
|
loadInitialData()
|
||||||
.then(() => {
|
.then((pendingData) => {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@@ -165,18 +174,13 @@ export function RouterProvider({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storageUtil
|
if (
|
||||||
.get('contextMenu/pendingData')
|
pendingData &&
|
||||||
.then((pendingData) => {
|
isValidPage(pendingData.featureKey) &&
|
||||||
if (
|
Date.now() - pendingData.timestamp < CONTEXT_MENU_DATA_EXPIRY_MS
|
||||||
pendingData &&
|
) {
|
||||||
isValidPage(pendingData.featureKey) &&
|
setCurrentPage(pendingData.featureKey as PageType);
|
||||||
Date.now() - pendingData.timestamp < CONTEXT_MENU_DATA_EXPIRY_MS
|
}
|
||||||
) {
|
|
||||||
setCurrentPage(pendingData.featureKey as PageType);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { storageUtil } from '@/utils/chromeStorage';
|
|||||||
import {
|
import {
|
||||||
applyResolvedThemeClass,
|
applyResolvedThemeClass,
|
||||||
getThemeSyncSnapshot,
|
getThemeSyncSnapshot,
|
||||||
|
hasThemeSyncSnapshot,
|
||||||
isValidThemeMode,
|
isValidThemeMode,
|
||||||
persistThemeModeSnapshot,
|
persistThemeModeSnapshot,
|
||||||
resolveThemeMode,
|
resolveThemeMode,
|
||||||
@@ -68,6 +69,10 @@ export function ThemeModeProvider({ children }: ThemeModeProviderProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (hasThemeSyncSnapshot()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
storageUtil
|
storageUtil
|
||||||
|
|||||||
@@ -7,10 +7,24 @@ import { storageUtil } from '@/utils/chromeStorage';
|
|||||||
vi.mock('@/utils/chromeStorage', () => ({
|
vi.mock('@/utils/chromeStorage', () => ({
|
||||||
storageUtil: {
|
storageUtil: {
|
||||||
get: vi.fn(),
|
get: vi.fn(),
|
||||||
|
getMany: vi.fn(),
|
||||||
set: vi.fn(() => Promise.resolve()),
|
set: vi.fn(() => Promise.resolve()),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/** 模拟批量 storage 读取,未指定的键由 Router 侧使用默认值 */
|
||||||
|
function mockStorageBatch(map: Record<string, unknown> = {}) {
|
||||||
|
(storageUtil.getMany as ReturnType<typeof vi.fn>).mockImplementation((keys: string[]) => {
|
||||||
|
const result: Record<string, unknown> = {};
|
||||||
|
for (const key of keys) {
|
||||||
|
if (key in map) {
|
||||||
|
result[key] = map[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const TestComponent = () => {
|
const TestComponent = () => {
|
||||||
const { currentPage, navigateTo, visiblePages, pageOrder } = useRouter();
|
const { currentPage, navigateTo, visiblePages, pageOrder } = useRouter();
|
||||||
return (
|
return (
|
||||||
@@ -46,9 +60,7 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('应该使用默认值初始化路由', async () => {
|
it('应该使用默认值初始化路由', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((_key: string, defaultValue: any) =>
|
mockStorageBatch();
|
||||||
Promise.resolve(defaultValue),
|
|
||||||
);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider defaultRoute="dashboard">
|
<RouterProvider defaultRoute="dashboard">
|
||||||
@@ -59,13 +71,18 @@ describe('RouterProvider', () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByTestId('current-page')).toHaveTextContent('dashboard');
|
expect(screen.getByTestId('current-page')).toHaveTextContent('dashboard');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(storageUtil.getMany).toHaveBeenCalledWith([
|
||||||
|
'app/currentRoute',
|
||||||
|
'app/visiblePages',
|
||||||
|
'app/pageOrder',
|
||||||
|
'app/recentlyUsedTools',
|
||||||
|
'contextMenu/pendingData',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('应该从指定的 syncKey 加载路由', async () => {
|
it('应该从指定的 syncKey 加载路由', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((key: string, defaultValue: any) => {
|
mockStorageBatch({ 'app/sidepanelRoute': 'timestamp' });
|
||||||
if (key === 'app/sidepanelRoute') return Promise.resolve('timestamp');
|
|
||||||
return Promise.resolve(defaultValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider syncKey="app/sidepanelRoute">
|
<RouterProvider syncKey="app/sidepanelRoute">
|
||||||
@@ -79,9 +96,7 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('导航时应该更新指定的 syncKey', async () => {
|
it('导航时应该更新指定的 syncKey', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((_key: string, defaultValue: any) =>
|
mockStorageBatch();
|
||||||
Promise.resolve(defaultValue),
|
|
||||||
);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider syncKey="app/popupRoute">
|
<RouterProvider syncKey="app/popupRoute">
|
||||||
@@ -104,10 +119,7 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('应该支持独立的标签页路由同步', async () => {
|
it('应该支持独立的标签页路由同步', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((key: string, defaultValue: any) => {
|
mockStorageBatch({ 'app/tabRoute': 'qrCode' });
|
||||||
if (key === 'app/tabRoute') return Promise.resolve('qrCode');
|
|
||||||
return Promise.resolve(defaultValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider syncKey="app/tabRoute">
|
<RouterProvider syncKey="app/tabRoute">
|
||||||
@@ -121,11 +133,9 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('应该独立支持 visiblePagesKey 和 pageOrderKey,并合并缺失的新功能', async () => {
|
it('应该独立支持 visiblePagesKey 和 pageOrderKey,并合并缺失的新功能', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((key: string, defaultValue: any) => {
|
mockStorageBatch({
|
||||||
if (key === 'app/sidepanelVisiblePages')
|
'app/sidepanelVisiblePages': ['timestamp', 'storageCleaner'],
|
||||||
return Promise.resolve(['timestamp', 'storageCleaner']);
|
'app/sidepanelPageOrder': ['storageCleaner', 'timestamp'],
|
||||||
if (key === 'app/sidepanelPageOrder') return Promise.resolve(['storageCleaner', 'timestamp']);
|
|
||||||
return Promise.resolve(defaultValue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@@ -167,10 +177,9 @@ describe('RouterProvider', () => {
|
|||||||
'jsonTools',
|
'jsonTools',
|
||||||
];
|
];
|
||||||
|
|
||||||
(storageUtil.get as any).mockImplementation((key: string, defaultValue: any) => {
|
mockStorageBatch({
|
||||||
if (key === 'app/popupVisiblePages') return Promise.resolve(oldVisiblePages);
|
'app/popupVisiblePages': oldVisiblePages,
|
||||||
if (key === 'app/popupPageOrder') return Promise.resolve(oldPageOrder);
|
'app/popupPageOrder': oldPageOrder,
|
||||||
return Promise.resolve(defaultValue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@@ -209,9 +218,7 @@ describe('RouterProvider', () => {
|
|||||||
localStorage.setItem('snapshot/app/visiblePages', JSON.stringify(oldVisiblePages));
|
localStorage.setItem('snapshot/app/visiblePages', JSON.stringify(oldVisiblePages));
|
||||||
localStorage.setItem('snapshot/app/pageOrder', JSON.stringify(oldPageOrder));
|
localStorage.setItem('snapshot/app/pageOrder', JSON.stringify(oldPageOrder));
|
||||||
|
|
||||||
(storageUtil.get as any).mockImplementation((_key: string, defaultValue: any) =>
|
mockStorageBatch();
|
||||||
Promise.resolve(defaultValue),
|
|
||||||
);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider>
|
<RouterProvider>
|
||||||
@@ -226,9 +233,7 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('storage.onChanged 同步 visiblePages 时应合并缺失的新功能', async () => {
|
it('storage.onChanged 同步 visiblePages 时应合并缺失的新功能', async () => {
|
||||||
(storageUtil.get as any).mockImplementation((_key: string, defaultValue: unknown) =>
|
mockStorageBatch();
|
||||||
Promise.resolve(defaultValue),
|
|
||||||
);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider visiblePagesKey="app/popupVisiblePages" pageOrderKey="app/popupPageOrder">
|
<RouterProvider visiblePagesKey="app/popupVisiblePages" pageOrderKey="app/popupPageOrder">
|
||||||
@@ -299,9 +304,9 @@ describe('RouterProvider', () => {
|
|||||||
resolveGet = resolve;
|
resolveGet = resolve;
|
||||||
});
|
});
|
||||||
|
|
||||||
(storageUtil.get as any).mockImplementation(async (key: string, defaultValue: unknown) => {
|
(storageUtil.getMany as ReturnType<typeof vi.fn>).mockImplementation(async () => {
|
||||||
await getBlocked;
|
await getBlocked;
|
||||||
return storage.get(key) ?? defaultValue;
|
return Object.fromEntries(storage.entries());
|
||||||
});
|
});
|
||||||
(storageUtil.set as any).mockImplementation(async (key: string, value: unknown) => {
|
(storageUtil.set as any).mockImplementation(async (key: string, value: unknown) => {
|
||||||
storage.set(key, value);
|
storage.set(key, value);
|
||||||
@@ -324,7 +329,9 @@ describe('RouterProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('初始化失败时仍应解除加载状态以便渲染页面', async () => {
|
it('初始化失败时仍应解除加载状态以便渲染页面', async () => {
|
||||||
(storageUtil.get as any).mockRejectedValue(new Error('Storage unavailable'));
|
(storageUtil.getMany as ReturnType<typeof vi.fn>).mockRejectedValue(
|
||||||
|
new Error('Storage unavailable'),
|
||||||
|
);
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<RouterProvider>
|
<RouterProvider>
|
||||||
@@ -344,10 +351,9 @@ describe('RouterProvider', () => {
|
|||||||
resolveGet = resolve;
|
resolveGet = resolve;
|
||||||
});
|
});
|
||||||
|
|
||||||
(storageUtil.get as any).mockImplementation(async (key: string, defaultValue: unknown) => {
|
(storageUtil.getMany as ReturnType<typeof vi.fn>).mockImplementation(async () => {
|
||||||
await getBlocked;
|
await getBlocked;
|
||||||
if (key === 'app/currentRoute') return 'dashboard';
|
return { 'app/currentRoute': 'dashboard' };
|
||||||
return defaultValue;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@@ -374,7 +380,7 @@ describe('RouterProvider', () => {
|
|||||||
resolveStorage = resolve;
|
resolveStorage = resolve;
|
||||||
});
|
});
|
||||||
|
|
||||||
(storageUtil.get as any).mockImplementation(() => storagePromise);
|
(storageUtil.getMany as ReturnType<typeof vi.fn>).mockImplementation(() => storagePromise);
|
||||||
|
|
||||||
const { unmount } = render(
|
const { unmount } = render(
|
||||||
<RouterProvider>
|
<RouterProvider>
|
||||||
@@ -383,7 +389,7 @@ describe('RouterProvider', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
unmount();
|
unmount();
|
||||||
resolveStorage!('dashboard');
|
resolveStorage!({});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ describe('ThemeModeProvider', () => {
|
|||||||
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
|
expect(screen.getByTestId('mode')).toHaveTextContent('dark');
|
||||||
expect(screen.getByTestId('resolved-mode')).toHaveTextContent('dark');
|
expect(screen.getByTestId('resolved-mode')).toHaveTextContent('dark');
|
||||||
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
||||||
|
expect(storageUtil.get).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('异步恢复 storage 后应写回 snapshot', async () => {
|
it('异步恢复 storage 后应写回 snapshot', async () => {
|
||||||
|
|||||||
@@ -75,6 +75,27 @@ describe('chromeStorage', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getMany', () => {
|
||||||
|
it('应该一次读取多个键', async () => {
|
||||||
|
(chrome.storage.local.get as any).mockResolvedValue({
|
||||||
|
'app/theme': 'dark',
|
||||||
|
'app/popupRoute': 'timestamp',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await storageUtil.getMany(['app/theme', 'app/popupRoute']);
|
||||||
|
|
||||||
|
expect(result).toEqual({ 'app/theme': 'dark', 'app/popupRoute': 'timestamp' });
|
||||||
|
expect(chrome.storage.local.get).toHaveBeenCalledWith(['app/theme', 'app/popupRoute']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('空键数组应直接返回空对象', async () => {
|
||||||
|
const result = await storageUtil.getMany([]);
|
||||||
|
|
||||||
|
expect(result).toEqual({});
|
||||||
|
expect(chrome.storage.local.get).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('get 类型签名', () => {
|
describe('get 类型签名', () => {
|
||||||
it('无默认值时应推断为可选返回类型', () => {
|
it('无默认值时应推断为可选返回类型', () => {
|
||||||
const _getWithoutDefault = () => storageUtil.get('app/theme');
|
const _getWithoutDefault = () => storageUtil.get('app/theme');
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ describe('useStorageState', () => {
|
|||||||
|
|
||||||
// 初始值应从快照恢复,而非默认值
|
// 初始值应从快照恢复,而非默认值
|
||||||
expect(result.current[0]).toBe(false);
|
expect(result.current[0]).toBe(false);
|
||||||
|
expect(storageUtil.get).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('应该从 Chrome Storage 异步加载并覆盖初始值', async () => {
|
it('应该从 Chrome Storage 异步加载并覆盖初始值', async () => {
|
||||||
@@ -179,5 +180,6 @@ describe('useStorageState', () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(storageUtil.set).not.toHaveBeenCalled();
|
expect(storageUtil.set).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
expect(storageUtil.get).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,13 +18,26 @@ class StorageUtils {
|
|||||||
key: K,
|
key: K,
|
||||||
defaultValue?: StorageSchema[K],
|
defaultValue?: StorageSchema[K],
|
||||||
): Promise<StorageSchema[K] | undefined> {
|
): Promise<StorageSchema[K] | undefined> {
|
||||||
const result = await chrome.storage.local.get([key]);
|
const result = await this.getMany([key]);
|
||||||
if (defaultValue !== undefined) {
|
if (defaultValue !== undefined) {
|
||||||
return (result[key] ?? defaultValue) as StorageSchema[K];
|
return (result[key] ?? defaultValue) as StorageSchema[K];
|
||||||
}
|
}
|
||||||
return result[key] as StorageSchema[K] | undefined;
|
return result[key] as StorageSchema[K] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量获取多个键(单次 IPC)
|
||||||
|
*/
|
||||||
|
async getMany<K extends keyof StorageSchema>(
|
||||||
|
keys: readonly K[],
|
||||||
|
): Promise<Partial<Pick<StorageSchema, K>>> {
|
||||||
|
if (keys.length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const result = await chrome.storage.local.get([...keys]);
|
||||||
|
return result as Partial<Pick<StorageSchema, K>>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置值
|
* 设置值
|
||||||
* @param key
|
* @param key
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* 检查 localStorage 中是否存在指定键的快照
|
||||||
|
*/
|
||||||
|
export function hasSyncSnapshot(key: string): boolean {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(`snapshot/${key}`) !== null;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 localStorage 获取同步快照(用于消除异步加载产生的首屏闪烁)
|
* 从 localStorage 获取同步快照(用于消除异步加载产生的首屏闪烁)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,6 +9,15 @@ const VALID_MODES: ThemeMode[] = ['light', 'dark', 'system'];
|
|||||||
export const isValidThemeMode = (value: unknown): value is ThemeMode =>
|
export const isValidThemeMode = (value: unknown): value is ThemeMode =>
|
||||||
VALID_MODES.includes(value as ThemeMode);
|
VALID_MODES.includes(value as ThemeMode);
|
||||||
|
|
||||||
|
/** 检查 localStorage 中是否存在主题快照 */
|
||||||
|
export const hasThemeSyncSnapshot = (): boolean => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(THEME_MODE_SNAPSHOT_KEY) !== null;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步读取 localStorage 快照(首屏防闪烁)
|
* 同步读取 localStorage 快照(首屏防闪烁)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
type SetStateAction,
|
type SetStateAction,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { storageUtil } from '@/utils/chromeStorage';
|
import { storageUtil } from '@/utils/chromeStorage';
|
||||||
import { getSyncSnapshot } from '@/utils/syncSnapshot';
|
import { getSyncSnapshot, hasSyncSnapshot } from '@/utils/syncSnapshot';
|
||||||
import type { StorageSchema } from '@/types/storage';
|
import type { StorageSchema } from '@/types/storage';
|
||||||
|
|
||||||
export const useStorageState = <K extends keyof StorageSchema>(
|
export const useStorageState = <K extends keyof StorageSchema>(
|
||||||
@@ -34,6 +34,14 @@ export const useStorageState = <K extends keyof StorageSchema>(
|
|||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
const loadState = async () => {
|
const loadState = async () => {
|
||||||
|
if (hasSyncSnapshot(key as string)) {
|
||||||
|
if (!cancelled) {
|
||||||
|
setIsInitialized(true);
|
||||||
|
hasLoadedFromStorage.current = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const savedValue = await storageUtil.get(key, defaultValue);
|
const savedValue = await storageUtil.get(key, defaultValue);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user