refactor: remove unnecessary useMemo calls across components

Replace over-cached simple computations with direct expressions:

- popup/App.tsx: getEntryPointType() and routerConfig (values are stable)
- Dashboard/index.tsx: visibleSet, visibleFeatures, recentFeatures
  (Set creation + array filter/map are cheaper than useMemo overhead)
- useTextStatistics.ts: getTextStats(text) (simple string processing)
- ThemeModeProvider.tsx: contextValue object (setMode is stable via useCallback)

-39 lines, +28 lines (net -11 lines)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
雨霖铃
2026-05-29 20:59:03 +08:00
parent 93019f56cf
commit b41cfb2a02
4 changed files with 29 additions and 47 deletions
+13 -17
View File
@@ -3,25 +3,21 @@ import TopBar from '@/components/TopBar';
import RouterContainer from '@/components/RouterContainer'; import RouterContainer from '@/components/RouterContainer';
import ErrorBoundary from '@/components/ErrorBoundary'; import ErrorBoundary from '@/components/ErrorBoundary';
import { getEntryPointType } from '@/config/features'; import { getEntryPointType } from '@/config/features';
import { useMemo } from 'react';
export default function App() { export default function App() {
const entryType = useMemo(() => getEntryPointType(), []); const entryType = getEntryPointType();
const routerConfig = useMemo(() => { const routerConfig =
if (entryType === 'tab') { entryType === 'tab'
return { ? {
syncKey: 'app/tabRoute' as const, syncKey: 'app/tabRoute' as const,
visiblePagesKey: 'app/tabVisiblePages' as const, visiblePagesKey: 'app/tabVisiblePages' as const,
pageOrderKey: 'app/tabPageOrder' as const, pageOrderKey: 'app/tabPageOrder' as const,
}; }
} : {
return { syncKey: 'app/popupRoute' as const,
syncKey: 'app/popupRoute' as const, visiblePagesKey: 'app/popupVisiblePages' as const,
visiblePagesKey: 'app/popupVisiblePages' as const, pageOrderKey: 'app/popupPageOrder' as const,
pageOrderKey: 'app/popupPageOrder' as const, };
};
}, [entryType]);
return ( return (
<RouterProvider <RouterProvider
+9 -14
View File
@@ -1,7 +1,6 @@
import { useRouter } from '@/providers/RouterProvider'; import { useRouter } from '@/providers/RouterProvider';
import { getFeatureByKey } from '@/config/features'; import { getFeatureByKey } from '@/config/features';
import type { PageType } from '@/types/storage'; import type { PageType } from '@/types/storage';
import { useMemo } from 'react';
import { useI18n } from '@/utils/chromeI18n'; import { useI18n } from '@/utils/chromeI18n';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
@@ -9,21 +8,17 @@ export default function Index() {
const { navigateTo, visiblePages, pageOrder, recentlyUsedTools } = useRouter(); const { navigateTo, visiblePages, pageOrder, recentlyUsedTools } = useRouter();
const { t } = useI18n(['features']); const { t } = useI18n(['features']);
const visibleSet = useMemo(() => new Set<string>(visiblePages), [visiblePages]); const visibleSet = new Set<string>(visiblePages);
const visibleFeatures = useMemo(() => { const visibleFeatures = pageOrder
return pageOrder .filter((key) => visibleSet.has(key))
.filter((key) => visibleSet.has(key)) .map((key) => ({ key, feature: getFeatureByKey(key) }))
.map((key) => ({ key, feature: getFeatureByKey(key) })) .filter((item) => item.feature?.themeColorKey && item.feature.icon != null);
.filter((item) => item.feature?.themeColorKey && item.feature.icon != null);
}, [pageOrder, visibleSet]);
const recentFeatures = useMemo(() => { const recentFeatures = recentlyUsedTools
return recentlyUsedTools .filter((key) => visibleSet.has(key))
.filter((key) => visibleSet.has(key)) .map((key) => ({ key, feature: getFeatureByKey(key) }))
.map((key) => ({ key, feature: getFeatureByKey(key) })) .filter((item) => item.feature?.themeColorKey && item.feature.icon != null);
.filter((item) => item.feature?.themeColorKey && item.feature.icon != null);
}, [recentlyUsedTools, visibleSet]);
const showRecent = recentFeatures.length > 0; const showRecent = recentFeatures.length > 0;
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useState } from 'react';
import { getTextStats, type TextStats } from '@/utils/textStatistics'; import { getTextStats, type TextStats } from '@/utils/textStatistics';
import { useContextMenuData } from '@/utils/useContextMenuData'; import { useContextMenuData } from '@/utils/useContextMenuData';
@@ -17,7 +17,7 @@ export function useTextStatistics(): UseTextStatisticsReturn {
useContextMenuData({ featureKey: 'textStatistics', onData: handleContextMenuData }); useContextMenuData({ featureKey: 'textStatistics', onData: handleContextMenuData });
const stats = useMemo(() => getTextStats(text), [text]); const stats = getTextStats(text);
return { text, stats, setText }; return { text, stats, setText };
} }
+5 -14
View File
@@ -1,12 +1,4 @@
import { import { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react';
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
import { browser } from 'wxt/browser'; import { browser } from 'wxt/browser';
import { storageUtil } from '@/utils/chromeStorage'; import { storageUtil } from '@/utils/chromeStorage';
@@ -141,12 +133,11 @@ export function ThemeModeProvider({ children }: ThemeModeProviderProps) {
} }
}, [resolvedMode]); }, [resolvedMode]);
const contextValue = useMemo( return (
() => ({ mode, resolvedMode, setMode }), <ThemeModeContext.Provider value={{ mode, resolvedMode, setMode }}>
[mode, resolvedMode, setMode], {children}
</ThemeModeContext.Provider>
); );
return <ThemeModeContext.Provider value={contextValue}>{children}</ThemeModeContext.Provider>;
} }
export function useThemeMode(): ThemeModeContextType { export function useThemeMode(): ThemeModeContextType {