refactor: Optimize message handling and event management
- Introduce messagesRef to track messages without causing re-renders - Simplify event listener management with more concise useEffect hooks - Improve auto-rename topic logic with current messages reference - Remove commented-out code and unused event listeners - Enhance type safety and reduce dependency complexity
This commit is contained in:
parent
49d29d78da
commit
3312befe11
@ -50,6 +50,12 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
const [hasMore, setHasMore] = useState(false)
|
const [hasMore, setHasMore] = useState(false)
|
||||||
const [isLoadingMore, setIsLoadingMore] = useState(false)
|
const [isLoadingMore, setIsLoadingMore] = useState(false)
|
||||||
|
|
||||||
|
const messagesRef = useRef<Message[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
messagesRef.current = messages
|
||||||
|
}, [messages])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const reversedMessages = [...messages].reverse()
|
const reversedMessages = [...messages].reverse()
|
||||||
const newDisplayMessages = reversedMessages.slice(0, displayCount)
|
const newDisplayMessages = reversedMessages.slice(0, displayCount)
|
||||||
@ -85,15 +91,8 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
setTimeout(() => containerRef.current?.scrollTo({ top: containerRef.current.scrollHeight, behavior: 'auto' }), 50)
|
setTimeout(() => containerRef.current?.scrollTo({ top: containerRef.current.scrollHeight, behavior: 'auto' }), 50)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// const onAppendMessageMemo = useCallback(
|
const autoRenameTopic = useCallback(async () => {
|
||||||
// async (message: Message) => {
|
const messages = messagesRef.current
|
||||||
// const newMessages = [...messages, message]
|
|
||||||
// await dispatch(updateMessages(topic, newMessages))
|
|
||||||
// },
|
|
||||||
// [topic, dispatch, messages]
|
|
||||||
// )
|
|
||||||
|
|
||||||
const autoRenameTopicMemo = useCallback(async () => {
|
|
||||||
const _topic = getTopic(assistant, topic.id)
|
const _topic = getTopic(assistant, topic.id)
|
||||||
|
|
||||||
if (!enableTopicNaming) {
|
if (!enableTopicNaming) {
|
||||||
@ -114,18 +113,16 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
updateTopic(data)
|
updateTopic(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [assistant, enableTopicNaming, messages, setActiveTopic, topic.id, updateTopic, t])
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [assistant, topic.id, enableTopicNaming, t, setActiveTopic])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const messages = messagesRef.current
|
||||||
|
|
||||||
const unsubscribes = [
|
const unsubscribes = [
|
||||||
// EventEmitter.on(EVENT_NAMES.APPEND_MESSAGE, onAppendMessageMemo),
|
|
||||||
// EventEmitter.on(EVENT_NAMES.RECEIVE_MESSAGE, () => {
|
|
||||||
// setTimeout(() => EventEmitter.emit(EVENT_NAMES.AI_AUTO_RENAME), 100)
|
|
||||||
// }),
|
|
||||||
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, () => {
|
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, () => {
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
}),
|
}),
|
||||||
EventEmitter.on(EVENT_NAMES.AI_AUTO_RENAME, autoRenameTopicMemo),
|
|
||||||
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => {
|
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => {
|
||||||
const defaultTopic = getDefaultTopic(assistant.id)
|
const defaultTopic = getDefaultTopic(assistant.id)
|
||||||
|
|
||||||
@ -172,12 +169,13 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
||||||
return () => {
|
return () => unsubscribes.forEach((unsub) => unsub())
|
||||||
for (const unsub of unsubscribes) {
|
}, [assistant, dispatch, handleDeleteMessage, scrollToBottom, topic, updateTopic])
|
||||||
unsub()
|
|
||||||
}
|
useEffect(() => {
|
||||||
}
|
const unsubscribes = [EventEmitter.on(EVENT_NAMES.AI_AUTO_RENAME, autoRenameTopic)]
|
||||||
}, [assistant, autoRenameTopicMemo, dispatch, messages, handleDeleteMessage, scrollToBottom, topic, updateTopic])
|
return () => unsubscribes.forEach((unsub) => unsub())
|
||||||
|
}, [autoRenameTopic])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
runAsyncFunction(async () => {
|
runAsyncFunction(async () => {
|
||||||
|
|||||||
@ -172,9 +172,13 @@ export const {
|
|||||||
|
|
||||||
const handleResponseMessageUpdate = (message, topicId, dispatch, getState) => {
|
const handleResponseMessageUpdate = (message, topicId, dispatch, getState) => {
|
||||||
dispatch(setStreamMessage({ topicId, message }))
|
dispatch(setStreamMessage({ topicId, message }))
|
||||||
|
|
||||||
// When message is complete, commit to messages and sync with DB
|
// When message is complete, commit to messages and sync with DB
|
||||||
if (message.status !== 'pending') {
|
if (message.status !== 'pending') {
|
||||||
EventEmitter.emit(EVENT_NAMES.AI_AUTO_RENAME)
|
if (message.status === 'success') {
|
||||||
|
EventEmitter.emit(EVENT_NAMES.AI_AUTO_RENAME)
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(commitStreamMessage({ topicId, messageId: message.id }))
|
dispatch(commitStreamMessage({ topicId, messageId: message.id }))
|
||||||
|
|
||||||
const state = getState()
|
const state = getState()
|
||||||
@ -225,7 +229,7 @@ export const sendMessage =
|
|||||||
// 使用用户消息
|
// 使用用户消息
|
||||||
let userMessage: Message
|
let userMessage: Message
|
||||||
if (isResend) {
|
if (isResend) {
|
||||||
userMessage = options.resendUserMessage
|
userMessage = options.resendUserMessage!
|
||||||
} else {
|
} else {
|
||||||
// 创建新的用户消息
|
// 创建新的用户消息
|
||||||
userMessage = getUserMessage({ assistant, topic, type: 'text', content })
|
userMessage = getUserMessage({ assistant, topic, type: 'text', content })
|
||||||
@ -233,9 +237,11 @@ export const sendMessage =
|
|||||||
if (options?.files) {
|
if (options?.files) {
|
||||||
userMessage.files = options.files
|
userMessage.files = options.files
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options?.knowledgeBaseIds) {
|
if (options?.knowledgeBaseIds) {
|
||||||
userMessage.knowledgeBaseIds = options.knowledgeBaseIds
|
userMessage.knowledgeBaseIds = options.knowledgeBaseIds
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options?.mentionModels) {
|
if (options?.mentionModels) {
|
||||||
userMessage.mentions = options.mentionModels
|
userMessage.mentions = options.mentionModels
|
||||||
}
|
}
|
||||||
@ -245,6 +251,7 @@ export const sendMessage =
|
|||||||
if (!isResend) {
|
if (!isResend) {
|
||||||
dispatch(addMessage({ topicId: topic.id, messages: userMessage }))
|
dispatch(addMessage({ topicId: topic.id, messages: userMessage }))
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE)
|
EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE)
|
||||||
|
|
||||||
// 处理助手消息
|
// 处理助手消息
|
||||||
@ -284,8 +291,12 @@ export const sendMessage =
|
|||||||
|
|
||||||
// Use topic queue to handle request
|
// Use topic queue to handle request
|
||||||
const queue = getTopicQueue(topic.id)
|
const queue = getTopicQueue(topic.id)
|
||||||
|
|
||||||
// let assistantMessage: Message | undefined
|
// let assistantMessage: Message | undefined
|
||||||
!isResend && dispatch(addMessage({ topicId: topic.id, messages: assistantMessages }))
|
if (!isResend) {
|
||||||
|
dispatch(addMessage({ topicId: topic.id, messages: assistantMessages }))
|
||||||
|
}
|
||||||
|
|
||||||
for (const assistantMessage of assistantMessages) {
|
for (const assistantMessage of assistantMessages) {
|
||||||
// console.log('assistantMessage', assistantMessage)
|
// console.log('assistantMessage', assistantMessage)
|
||||||
|
|
||||||
@ -295,9 +306,11 @@ export const sendMessage =
|
|||||||
// Sync user message with database
|
// Sync user message with database
|
||||||
const state = getState()
|
const state = getState()
|
||||||
const currentTopicMessages = state.messages.messagesByTopic[topic.id]
|
const currentTopicMessages = state.messages.messagesByTopic[topic.id]
|
||||||
|
|
||||||
if (currentTopicMessages) {
|
if (currentTopicMessages) {
|
||||||
await syncMessagesWithDB(topic.id, currentTopicMessages)
|
await syncMessagesWithDB(topic.id, currentTopicMessages)
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.add(async () => {
|
queue.add(async () => {
|
||||||
try {
|
try {
|
||||||
const state = getState()
|
const state = getState()
|
||||||
@ -340,7 +353,7 @@ export const sendMessage =
|
|||||||
throttledDispatch({ ...assistantMessage, ...updatedMsg }, topic.id, dispatch, getState)
|
throttledDispatch({ ...assistantMessage, ...updatedMsg }, topic.id, dispatch, getState)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Error in chat completion:', error)
|
console.error('Error in chat completion:', error)
|
||||||
dispatch(
|
dispatch(
|
||||||
updateMessage({
|
updateMessage({
|
||||||
@ -354,7 +367,7 @@ export const sendMessage =
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Error in sendMessage:', error)
|
console.error('Error in sendMessage:', error)
|
||||||
dispatch(setError(error.message))
|
dispatch(setError(error.message))
|
||||||
} finally {
|
} finally {
|
||||||
@ -409,7 +422,7 @@ export const resendMessage =
|
|||||||
resendAssistantMessage: message
|
resendAssistantMessage: message
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Error in resendMessage:', error)
|
console.error('Error in resendMessage:', error)
|
||||||
dispatch(setError(error.message))
|
dispatch(setError(error.message))
|
||||||
} finally {
|
} finally {
|
||||||
@ -477,7 +490,10 @@ export const selectTopicMessages = createSelector(
|
|||||||
[(state: RootState) => state.messages, (_, topicId: string) => topicId],
|
[(state: RootState) => state.messages, (_, topicId: string) => topicId],
|
||||||
(messagesState, topicId) => {
|
(messagesState, topicId) => {
|
||||||
const topicMessages = messagesState.messagesByTopic[topicId]
|
const topicMessages = messagesState.messagesByTopic[topicId]
|
||||||
if (!topicMessages) return []
|
|
||||||
|
if (!topicMessages) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
return [...topicMessages].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
|
return [...topicMessages].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
|
||||||
}
|
}
|
||||||
@ -503,7 +519,9 @@ export const selectError = (state: RootState): string | null => {
|
|||||||
return messagesState?.error || null
|
return messagesState?.error || null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectStreamMessage = (state: RootState, topicId: string, messageId: string): Message | null =>
|
export const selectStreamMessage = (state: RootState, topicId: string, messageId: string): Message | null => {
|
||||||
state.messages.streamMessagesByTopic[topicId]?.[messageId] || null
|
const messagesState = state.messages as MessagesState
|
||||||
|
return messagesState.streamMessagesByTopic[topicId]?.[messageId] || null
|
||||||
|
}
|
||||||
|
|
||||||
export default messagesSlice.reducer
|
export default messagesSlice.reducer
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user