From 51720296ccaaae19da2808516894781fe33781b3 Mon Sep 17 00:00:00 2001 From: xmk23333 Date: Mon, 8 Dec 2025 16:53:00 +0800 Subject: [PATCH] fix: optimize connections page performance and state management --- src/main/utils/template.ts | 1 + src/renderer/src/pages/connections.tsx | 94 +++++++++++++++----------- src/renderer/src/pages/mihomo.tsx | 4 -- 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/main/utils/template.ts b/src/main/utils/template.ts index cb7db1c..53648f2 100644 --- a/src/main/utils/template.ts +++ b/src/main/utils/template.ts @@ -9,6 +9,7 @@ export const defaultConfig: IAppConfig = { appTheme: 'system', useWindowFrame: false, proxyInTray: true, + showCurrentProxyInTray: false, disableTrayIconColor: false, maxLogDays: 7, proxyCols: 'auto', diff --git a/src/renderer/src/pages/connections.tsx b/src/renderer/src/pages/connections.tsx index fb79c68..f75f780 100644 --- a/src/renderer/src/pages/connections.tsx +++ b/src/renderer/src/pages/connections.tsx @@ -1,6 +1,6 @@ import BasePage from '@renderer/components/base/base-page' import { mihomoCloseAllConnections, mihomoCloseConnection } from '@renderer/utils/ipc' -import { Key, useCallback, useEffect, useMemo, useState } from 'react' +import { Key, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Badge, Button, Divider, Input, Select, SelectItem, Tab, Tabs } from '@heroui/react' import { calcTraffic } from '@renderer/utils/calc' import ConnectionItem from '@renderer/components/connections/connection-item' @@ -48,6 +48,13 @@ const Connections: React.FC = () => { const [viewMode, setViewMode] = useState<'list' | 'table'>(connectionViewMode) const [visibleColumns, setVisibleColumns] = useState>(new Set(connectionTableColumns)) + const activeConnectionsRef = useRef(activeConnections) + const allConnectionsRef = useRef(allConnections) + useEffect(() => { + activeConnectionsRef.current = activeConnections + allConnectionsRef.current = allConnections + }, [activeConnections, allConnections]) + const handleColumnWidthChange = useCallback(async (widths: Record) => { await patchAppConfig({ connectionTableColumnWidths: widths }) }, [patchAppConfig]) @@ -98,71 +105,80 @@ const Connections: React.FC = () => { const closeAllConnections = useCallback((): void => { tab === 'active' ? mihomoCloseAllConnections() : trashAllClosedConnection() - }, [tab, closedConnections]) + }, [tab]) const closeConnection = useCallback((id: string): void => { tab === 'active' ? mihomoCloseConnection(id) : trashClosedConnection(id) }, [tab]) const trashAllClosedConnection = (): void => { - const trashIds = closedConnections.map((conn) => conn.id) - setAllConnections((allConns) => allConns.filter((conn) => !trashIds.includes(conn.id))) - setClosedConnections([]) - - cachedConnections = allConnections + setClosedConnections((closedConns) => { + const trashIds = new Set(closedConns.map((conn) => conn.id)) + setAllConnections((allConns) => { + const filtered = allConns.filter((conn) => !trashIds.has(conn.id)) + cachedConnections = filtered + return filtered + }) + return [] + }) } const trashClosedConnection = (id: string): void => { - setAllConnections((allConns) => allConns.filter((conn) => conn.id != id)) - setClosedConnections((closedConns) => closedConns.filter((conn) => conn.id != id)) - - cachedConnections = allConnections + setAllConnections((allConns) => { + const filtered = allConns.filter((conn) => conn.id !== id) + cachedConnections = filtered + return filtered + }) + setClosedConnections((closedConns) => closedConns.filter((conn) => conn.id !== id)) } useEffect(() => { - if (isPaused) return - window.electron.ipcRenderer.on('mihomoConnections', (_e, info: IMihomoConnectionsInfo) => { + const handler = (_e: unknown, info: IMihomoConnectionsInfo): void => { setConnectionsInfo(info) if (!info.connections) return - const allConns = unionWith(activeConnections, allConnections, (a, b) => a.id === b.id) + const allConns = unionWith( + activeConnectionsRef.current, + allConnectionsRef.current, + (a, b) => a.id === b.id + ) + const prevConnMap = new Map(activeConnectionsRef.current.map((c) => [c.id, c])) const activeConns = info.connections.map((conn) => { - const preConn = activeConnections.find((c) => c.id === conn.id) - const downloadSpeed = preConn ? conn.download - preConn.download : 0 - const uploadSpeed = preConn ? conn.upload - preConn.upload : 0 + const preConn = prevConnMap.get(conn.id) return { ...conn, isActive: true, - downloadSpeed: downloadSpeed, - uploadSpeed: uploadSpeed + downloadSpeed: preConn ? conn.download - preConn.download : 0, + uploadSpeed: preConn ? conn.upload - preConn.upload : 0 } }) const closedConns = differenceWith(allConns, activeConns, (a, b) => a.id === b.id).map( - (conn) => { - return { - ...conn, - isActive: false, - downloadSpeed: 0, - uploadSpeed: 0 - } - } + (conn) => ({ + ...conn, + isActive: false, + downloadSpeed: 0, + uploadSpeed: 0 + }) ) setActiveConnections(activeConns) setClosedConnections(closedConns) setAllConnections(allConns.slice(-(activeConns.length + 200))) + cachedConnections = allConns + } - cachedConnections = allConnections - }) + if (!isPaused) { + window.electron.ipcRenderer.on('mihomoConnections', handler) + } return (): void => { window.electron.ipcRenderer.removeAllListeners('mihomoConnections') } - }, [allConnections, activeConnections, closedConnections, isPaused]) - const togglePause = () => { - setIsPaused(!isPaused) - } + }, [isPaused]) + const togglePause = useCallback(() => { + setIsPaused((prev) => !prev) + }, []) return ( { color="primary" variant="flat" showOutline={false} - content={`${filteredConnections.length}`} + content={filteredConnections.length} >