From b41cfb2a020e0a6fd5f4ba0a8f979b3759c46ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Fri, 29 May 2026 20:59:03 +0800 Subject: [PATCH] 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 --- src/entrypoints/popup/App.tsx | 30 ++++++++----------- src/pages/Dashboard/index.tsx | 23 ++++++-------- src/pages/TextStatistics/useTextStatistics.ts | 4 +-- src/providers/ThemeModeProvider.tsx | 19 ++++-------- 4 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/entrypoints/popup/App.tsx b/src/entrypoints/popup/App.tsx index a245d48..413568a 100644 --- a/src/entrypoints/popup/App.tsx +++ b/src/entrypoints/popup/App.tsx @@ -3,25 +3,21 @@ import TopBar from '@/components/TopBar'; import RouterContainer from '@/components/RouterContainer'; import ErrorBoundary from '@/components/ErrorBoundary'; import { getEntryPointType } from '@/config/features'; -import { useMemo } from 'react'; - export default function App() { - const entryType = useMemo(() => getEntryPointType(), []); + const entryType = getEntryPointType(); - const routerConfig = useMemo(() => { - if (entryType === 'tab') { - return { - syncKey: 'app/tabRoute' as const, - visiblePagesKey: 'app/tabVisiblePages' as const, - pageOrderKey: 'app/tabPageOrder' as const, - }; - } - return { - syncKey: 'app/popupRoute' as const, - visiblePagesKey: 'app/popupVisiblePages' as const, - pageOrderKey: 'app/popupPageOrder' as const, - }; - }, [entryType]); + const routerConfig = + entryType === 'tab' + ? { + syncKey: 'app/tabRoute' as const, + visiblePagesKey: 'app/tabVisiblePages' as const, + pageOrderKey: 'app/tabPageOrder' as const, + } + : { + syncKey: 'app/popupRoute' as const, + visiblePagesKey: 'app/popupVisiblePages' as const, + pageOrderKey: 'app/popupPageOrder' as const, + }; return ( new Set(visiblePages), [visiblePages]); + const visibleSet = new Set(visiblePages); - const visibleFeatures = useMemo(() => { - return pageOrder - .filter((key) => visibleSet.has(key)) - .map((key) => ({ key, feature: getFeatureByKey(key) })) - .filter((item) => item.feature?.themeColorKey && item.feature.icon != null); - }, [pageOrder, visibleSet]); + const visibleFeatures = pageOrder + .filter((key) => visibleSet.has(key)) + .map((key) => ({ key, feature: getFeatureByKey(key) })) + .filter((item) => item.feature?.themeColorKey && item.feature.icon != null); - const recentFeatures = useMemo(() => { - return recentlyUsedTools - .filter((key) => visibleSet.has(key)) - .map((key) => ({ key, feature: getFeatureByKey(key) })) - .filter((item) => item.feature?.themeColorKey && item.feature.icon != null); - }, [recentlyUsedTools, visibleSet]); + const recentFeatures = recentlyUsedTools + .filter((key) => visibleSet.has(key)) + .map((key) => ({ key, feature: getFeatureByKey(key) })) + .filter((item) => item.feature?.themeColorKey && item.feature.icon != null); const showRecent = recentFeatures.length > 0; diff --git a/src/pages/TextStatistics/useTextStatistics.ts b/src/pages/TextStatistics/useTextStatistics.ts index 78e5a1c..2ca8339 100644 --- a/src/pages/TextStatistics/useTextStatistics.ts +++ b/src/pages/TextStatistics/useTextStatistics.ts @@ -1,4 +1,4 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useState } from 'react'; import { getTextStats, type TextStats } from '@/utils/textStatistics'; import { useContextMenuData } from '@/utils/useContextMenuData'; @@ -17,7 +17,7 @@ export function useTextStatistics(): UseTextStatisticsReturn { useContextMenuData({ featureKey: 'textStatistics', onData: handleContextMenuData }); - const stats = useMemo(() => getTextStats(text), [text]); + const stats = getTextStats(text); return { text, stats, setText }; } diff --git a/src/providers/ThemeModeProvider.tsx b/src/providers/ThemeModeProvider.tsx index 7a7b75c..02b7997 100644 --- a/src/providers/ThemeModeProvider.tsx +++ b/src/providers/ThemeModeProvider.tsx @@ -1,12 +1,4 @@ -import { - createContext, - ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react'; +import { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react'; import { browser } from 'wxt/browser'; import { storageUtil } from '@/utils/chromeStorage'; @@ -141,12 +133,11 @@ export function ThemeModeProvider({ children }: ThemeModeProviderProps) { } }, [resolvedMode]); - const contextValue = useMemo( - () => ({ mode, resolvedMode, setMode }), - [mode, resolvedMode, setMode], + return ( + + {children} + ); - - return {children}; } export function useThemeMode(): ThemeModeContextType {