perf: prevent unnecessary topic rerendering (#8116)

This commit is contained in:
one 2025-07-14 13:43:01 +08:00 committed by GitHub
parent 19a8d9e9b3
commit c6554c8f80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 16 deletions

View File

@ -18,8 +18,8 @@ import { getStoreSetting } from './useSettings'
let _activeTopic: Topic let _activeTopic: Topic
let _setActiveTopic: (topic: Topic) => void let _setActiveTopic: (topic: Topic) => void
export function useActiveTopic(_assistant: Assistant, topic?: Topic) { export function useActiveTopic(assistantId: string, topic?: Topic) {
const { assistant } = useAssistant(_assistant.id) const { assistant } = useAssistant(assistantId)
const [activeTopic, setActiveTopic] = useState(topic || _activeTopic || assistant?.topics[0]) const [activeTopic, setActiveTopic] = useState(topic || _activeTopic || assistant?.topics[0])
_activeTopic = activeTopic _activeTopic = activeTopic

View File

@ -3,8 +3,8 @@ import { useSettings } from '@renderer/hooks/useSettings'
import { useActiveTopic } from '@renderer/hooks/useTopic' import { useActiveTopic } from '@renderer/hooks/useTopic'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import NavigationService from '@renderer/services/NavigationService' import NavigationService from '@renderer/services/NavigationService'
import { Assistant } from '@renderer/types' import { Assistant, Topic } from '@renderer/types'
import { FC, useEffect, useState } from 'react' import { FC, startTransition, useCallback, useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import styled from 'styled-components' import styled from 'styled-components'
@ -21,12 +21,31 @@ const HomePage: FC = () => {
const location = useLocation() const location = useLocation()
const state = location.state const state = location.state
const [activeAssistant, setActiveAssistant] = useState(state?.assistant || _activeAssistant || assistants[0]) const [activeAssistant, _setActiveAssistant] = useState(state?.assistant || _activeAssistant || assistants[0])
const { activeTopic, setActiveTopic } = useActiveTopic(activeAssistant, state?.topic) const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id, state?.topic)
const { showAssistants, showTopics, topicPosition } = useSettings() const { showAssistants, showTopics, topicPosition } = useSettings()
_activeAssistant = activeAssistant _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(() => { useEffect(() => {
NavigationService.setNavigate(navigate) NavigationService.setNavigate(navigate)
}, [navigate]) }, [navigate])

View File

@ -39,7 +39,7 @@ import { Dropdown, MenuProps, Tooltip } from 'antd'
import { ItemType, MenuItemType } from 'antd/es/menu/interface' import { ItemType, MenuItemType } from 'antd/es/menu/interface'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { findIndex } from 'lodash' 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 { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import styled from 'styled-components' import styled from 'styled-components'
@ -168,9 +168,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
const onSwitchTopic = useCallback( const onSwitchTopic = useCallback(
async (topic: Topic) => { async (topic: Topic) => {
// await modelGenerating() // await modelGenerating()
startTransition(() => { setActiveTopic(topic)
setActiveTopic(topic)
})
}, },
[setActiveTopic] [setActiveTopic]
) )

View File

@ -25,7 +25,7 @@ import { hasTopicPendingRequests } from '@renderer/utils/queue'
import { Dropdown, MenuProps } from 'antd' import { Dropdown, MenuProps } from 'antd'
import { omit } from 'lodash' import { omit } from 'lodash'
import { AlignJustify, Plus, Settings2, Tag, Tags } from 'lucide-react' 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 { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import * as tinyPinyin from 'tiny-pinyin' import * as tinyPinyin from 'tiny-pinyin'
@ -125,12 +125,8 @@ const AssistantItem: FC<AssistantItemProps> = ({
if (topicPosition === 'left') { if (topicPosition === 'left') {
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR) EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
} }
onSwitch(assistant)
} else {
startTransition(() => {
onSwitch(assistant)
})
} }
onSwitch(assistant)
}, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition]) }, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition])
const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name, t]) const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name, t])