perf: optimize connection and log components with memoization and state management

This commit is contained in:
xmk23333 2025-12-08 19:58:57 +08:00
parent 67aa17f6bb
commit 8f2e956fd0
3 changed files with 17 additions and 16 deletions

View File

@ -1,26 +1,19 @@
import { Button, Card, CardFooter, CardHeader, Chip } from '@heroui/react' import { Button, Card, CardFooter, CardHeader, Chip } from '@heroui/react'
import { calcTraffic } from '@renderer/utils/calc' import { calcTraffic } from '@renderer/utils/calc'
import dayjs from '@renderer/utils/dayjs' import dayjs from '@renderer/utils/dayjs'
import React, { useEffect } from 'react' import React from 'react'
import { CgClose, CgTrash } from 'react-icons/cg' import { CgClose, CgTrash } from 'react-icons/cg'
interface Props { interface Props {
index: number index: number
info: IMihomoConnectionDetail info: IMihomoConnectionDetail
selected: IMihomoConnectionDetail | undefined
setSelected: React.Dispatch<React.SetStateAction<IMihomoConnectionDetail | undefined>> setSelected: React.Dispatch<React.SetStateAction<IMihomoConnectionDetail | undefined>>
setIsDetailModalOpen: React.Dispatch<React.SetStateAction<boolean>> setIsDetailModalOpen: React.Dispatch<React.SetStateAction<boolean>>
close: (id: string) => void close: (id: string) => void
} }
const ConnectionItem: React.FC<Props> = (props) => { const ConnectionItem: React.FC<Props> = (props) => {
const { index, info, close, selected, setSelected, setIsDetailModalOpen } = props const { index, info, close, setSelected, setIsDetailModalOpen } = props
useEffect(() => {
if (selected?.id === info.id) {
setSelected(info)
}
}, [info])
return ( return (
<div className={`px-2 pb-2 ${index === 0 ? 'pt-2' : ''}`}> <div className={`px-2 pb-2 ${index === 0 ? 'pt-2' : ''}`}>
@ -37,7 +30,7 @@ const ConnectionItem: React.FC<Props> = (props) => {
<div className="w-full pr-12"> <div className="w-full pr-12">
<CardHeader className="pb-0 gap-1"> <CardHeader className="pb-0 gap-1">
<Chip <Chip
color={`${info.isActive ? 'primary' : 'danger'}`} color={info.isActive ? 'primary' : 'danger'}
size="sm" size="sm"
radius="sm" radius="sm"
variant="dot" variant="dot"
@ -84,7 +77,7 @@ const ConnectionItem: React.FC<Props> = (props) => {
</div> </div>
</Card> </Card>
<Button <Button
color={`${info.isActive ? 'warning' : 'danger'}`} color={info.isActive ? 'warning' : 'danger'}
variant="light" variant="light"
isIconOnly isIconOnly
className="absolute right-2 top-1/2 -translate-y-1/2" className="absolute right-2 top-1/2 -translate-y-1/2"

View File

@ -14,7 +14,7 @@ const LogItem: React.FC<IMihomoLogInfo & { index: number }> = (props) => {
<Card> <Card>
<CardHeader className="pb-0 pt-1"> <CardHeader className="pb-0 pt-1">
<div className={`mr-2 text-lg font-bold text-${colorMap[type]}`}> <div className={`mr-2 text-lg font-bold text-${colorMap[type]}`}>
{props.type.toUpperCase()} {type.toUpperCase()}
</div> </div>
<small className="text-foreground-500">{time}</small> <small className="text-foreground-500">{time}</small>
</CardHeader> </CardHeader>
@ -24,4 +24,4 @@ const LogItem: React.FC<IMihomoLogInfo & { index: number }> = (props) => {
) )
} }
export default LogItem export default React.memo(LogItem)

View File

@ -55,6 +55,15 @@ const Connections: React.FC = () => {
allConnectionsRef.current = allConnections allConnectionsRef.current = allConnections
}, [activeConnections, allConnections]) }, [activeConnections, allConnections])
const selectedConnection = useMemo(() => {
if (!selected) return undefined
return (
activeConnections.find((c) => c.id === selected.id) ||
closedConnections.find((c) => c.id === selected.id) ||
selected
)
}, [selected, activeConnections, closedConnections])
const handleColumnWidthChange = useCallback(async (widths: Record<string, number>) => { const handleColumnWidthChange = useCallback(async (widths: Record<string, number>) => {
await patchAppConfig({ connectionTableColumnWidths: widths }) await patchAppConfig({ connectionTableColumnWidths: widths })
}, [patchAppConfig]) }, [patchAppConfig])
@ -246,8 +255,8 @@ const Connections: React.FC = () => {
</div> </div>
} }
> >
{isDetailModalOpen && selected && ( {isDetailModalOpen && selectedConnection && (
<ConnectionDetailModal onClose={() => setIsDetailModalOpen(false)} connection={selected} /> <ConnectionDetailModal onClose={() => setIsDetailModalOpen(false)} connection={selectedConnection} />
)} )}
<div className="overflow-x-auto sticky top-0 z-40"> <div className="overflow-x-auto sticky top-0 z-40">
<div className="flex p-2 gap-2"> <div className="flex p-2 gap-2">
@ -403,7 +412,6 @@ const Connections: React.FC = () => {
<ConnectionItem <ConnectionItem
setSelected={setSelected} setSelected={setSelected}
setIsDetailModalOpen={setIsDetailModalOpen} setIsDetailModalOpen={setIsDetailModalOpen}
selected={selected}
close={closeConnection} close={closeConnection}
index={i} index={i}
key={connection.id} key={connection.id}