From c6554c8f80964ac4b9508ca4f4e31709a248f487 Mon Sep 17 00:00:00 2001 From: one Date: Mon, 14 Jul 2025 13:43:01 +0800 Subject: [PATCH] perf: prevent unnecessary topic rerendering (#8116) --- src/renderer/src/hooks/useTopic.ts | 4 +-- src/renderer/src/pages/home/HomePage.tsx | 27 ++++++++++++++++--- .../src/pages/home/Tabs/TopicsTab.tsx | 6 ++--- .../home/Tabs/components/AssistantItem.tsx | 8 ++---- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/renderer/src/hooks/useTopic.ts b/src/renderer/src/hooks/useTopic.ts index e6fea6f69a..ecd03bd89f 100644 --- a/src/renderer/src/hooks/useTopic.ts +++ b/src/renderer/src/hooks/useTopic.ts @@ -18,8 +18,8 @@ import { getStoreSetting } from './useSettings' let _activeTopic: Topic let _setActiveTopic: (topic: Topic) => void -export function useActiveTopic(_assistant: Assistant, topic?: Topic) { - const { assistant } = useAssistant(_assistant.id) +export function useActiveTopic(assistantId: string, topic?: Topic) { + const { assistant } = useAssistant(assistantId) const [activeTopic, setActiveTopic] = useState(topic || _activeTopic || assistant?.topics[0]) _activeTopic = activeTopic diff --git a/src/renderer/src/pages/home/HomePage.tsx b/src/renderer/src/pages/home/HomePage.tsx index 3bc47468fd..2a8f946c65 100644 --- a/src/renderer/src/pages/home/HomePage.tsx +++ b/src/renderer/src/pages/home/HomePage.tsx @@ -3,8 +3,8 @@ import { useSettings } from '@renderer/hooks/useSettings' import { useActiveTopic } from '@renderer/hooks/useTopic' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import NavigationService from '@renderer/services/NavigationService' -import { Assistant } from '@renderer/types' -import { FC, useEffect, useState } from 'react' +import { Assistant, Topic } from '@renderer/types' +import { FC, startTransition, useCallback, useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import styled from 'styled-components' @@ -21,12 +21,31 @@ const HomePage: FC = () => { const location = useLocation() const state = location.state - const [activeAssistant, setActiveAssistant] = useState(state?.assistant || _activeAssistant || assistants[0]) - const { activeTopic, setActiveTopic } = useActiveTopic(activeAssistant, state?.topic) + const [activeAssistant, _setActiveAssistant] = useState(state?.assistant || _activeAssistant || assistants[0]) + const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id, state?.topic) const { showAssistants, showTopics, topicPosition } = useSettings() _activeAssistant = activeAssistant + const setActiveAssistant = useCallback( + (newAssistant: Assistant) => { + startTransition(() => { + _setActiveAssistant(newAssistant) + // 同步更新 active topic,避免不必要的重新渲染 + const newTopic = newAssistant.topics[0] + _setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic)) + }) + }, + [_setActiveTopic] + ) + + const setActiveTopic = useCallback( + (newTopic: Topic) => { + startTransition(() => _setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic))) + }, + [_setActiveTopic] + ) + useEffect(() => { NavigationService.setNavigate(navigate) }, [navigate]) diff --git a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx index 74957692a0..d296ccdcf9 100644 --- a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx @@ -39,7 +39,7 @@ import { Dropdown, MenuProps, Tooltip } from 'antd' import { ItemType, MenuItemType } from 'antd/es/menu/interface' import dayjs from 'dayjs' import { findIndex } from 'lodash' -import { FC, startTransition, useCallback, useDeferredValue, useMemo, useRef, useState } from 'react' +import { FC, useCallback, useDeferredValue, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' import styled from 'styled-components' @@ -168,9 +168,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic const onSwitchTopic = useCallback( async (topic: Topic) => { // await modelGenerating() - startTransition(() => { - setActiveTopic(topic) - }) + setActiveTopic(topic) }, [setActiveTopic] ) diff --git a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx index 518473bb14..f0ae3e8883 100644 --- a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx @@ -25,7 +25,7 @@ import { hasTopicPendingRequests } from '@renderer/utils/queue' import { Dropdown, MenuProps } from 'antd' import { omit } from 'lodash' import { AlignJustify, Plus, Settings2, Tag, Tags } from 'lucide-react' -import { FC, memo, startTransition, useCallback, useEffect, useMemo, useState } from 'react' +import { FC, memo, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' import * as tinyPinyin from 'tiny-pinyin' @@ -125,12 +125,8 @@ const AssistantItem: FC = ({ if (topicPosition === 'left') { EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR) } - onSwitch(assistant) - } else { - startTransition(() => { - onSwitch(assistant) - }) } + onSwitch(assistant) }, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition]) const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name, t])