From e4b00044b1a552b2beeaecfbbca5635e61a4195e Mon Sep 17 00:00:00 2001 From: 222 <113026578+222chaos@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:36:09 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20fix:=20chatList=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=8E=E6=BB=91=E5=8A=A8=E5=88=B0=E5=BA=95=E9=83=A8?= =?UTF-8?q?=20(#310)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ⚡️ fix: chatList更新后滑动到底部 * ⚡️ fix: 简化chatlist逻辑 --- src/components/ChatList/index.tsx | 31 -------- src/components/ProChat/index.tsx | 10 +-- src/hooks/useChatList.ts | 128 ++++++++++++------------------ 3 files changed, 54 insertions(+), 115 deletions(-) diff --git a/src/components/ChatList/index.tsx b/src/components/ChatList/index.tsx index cb2a02f..776ce3b 100644 --- a/src/components/ChatList/index.tsx +++ b/src/components/ChatList/index.tsx @@ -16,7 +16,6 @@ import { useStyle } from './style'; export type ChatListProps = { chatList: ChatMessage[]; chatListRef: MutableRefObject; - loadingMessage?: ChatMessage; loading: boolean; className?: string; chatItemRenderConfig: ChatItemProps['chatItemRenderConfig']; @@ -50,7 +49,6 @@ const ChatList: React.FC = (props) => { chatListItemAvatarClassName, chatListItemContentClassName, chatListItemTitleClassName, - loadingMessage, userMeta = { avatar: DEFAULT_USER_AVATAR, }, @@ -104,35 +102,6 @@ const ChatList: React.FC = (props) => { ); })} - {loadingMessage && ( - - - - )} , ); }; diff --git a/src/components/ProChat/index.tsx b/src/components/ProChat/index.tsx index ba91b66..092dce7 100644 --- a/src/components/ProChat/index.tsx +++ b/src/components/ProChat/index.tsx @@ -378,8 +378,8 @@ export function ProChat< const { chatList, - loadingMessage, loading, + isLoadingMessage, setMessageItem, stopGenerateMessage, clearMessage, @@ -410,8 +410,6 @@ export function ProChat< : undefined, }); - const getChatLoadingMessage = useRefFunction(() => loadingMessage); - const getChatList = useRefFunction(() => { return chatList; }); @@ -422,7 +420,6 @@ export function ProChat< clearMessage, sendMessage, getChatList, - getChatLoadingMessage, setMessageItem, genMessageRecord, scrollToBottom: () => { @@ -456,7 +453,7 @@ export function ProChat< top: chatListContainerRef.current.scrollHeight, }); } - }, [loadingMessage]); + }, [chatList]); const backBottomDom = useMemo(() => { if (!isInitRender) return null; @@ -497,7 +494,6 @@ export function ProChat< userMeta={userMeta} assistantMeta={assistantMeta} loading={loading} - loadingMessage={loadingMessage} chatItemRenderConfig={chatItemRenderConfig} style={{ ...styles?.chatList, @@ -520,7 +516,7 @@ export function ProChat< {backBottomDom} { let controller = useRef(null); - const loadingMessageRef = useRef | undefined>(undefined); - - const [loadingMessage, setLoadingMessage] = useMergedState | undefined>( - undefined, - { - postState: (value) => { - loadingMessageRef.current = value; - return value; - }, - }, - ); - - const getLoadingMessage = useRefFunction(() => { - return loadingMessageRef.current; - }); - const chatListRef = useRef[]>([]); /** * Custom hook for managing the chat list. @@ -144,7 +128,7 @@ export const useChatList = (props: ProChatUIUseListChatProps) => { const [loading, setLoading] = useMergedState(true, { value: props.loading, }); - + const [isLoadingMessage, setIsLoadingMessage] = useMergedState(false); /** * Fetches the chat list using the provided request function. * If the request function is not provided, it sets the loading state to false and returns. @@ -198,7 +182,9 @@ export const useChatList = (props: ProChatUIUseListChatProps) => { */ const sendMessage = useRefFunction(async (message: string | Partial) => { controller.current = new AbortController(); - chatList.push( + + setChatList((prevState) => [ + ...prevState, genMessageRecord( typeof message === 'string' ? { content: message } @@ -208,22 +194,24 @@ export const useChatList = (props: ProChatUIUseListChatProps) => { }, 'user', ), - ); - setChatList([...chatList]); + ]); + if (!props?.sendMessageRequest) return; - setLoadingMessage( + setIsLoadingMessage(true); + setChatList((prevState) => [ + ...prevState, genMessageRecord( { content: LOADING_FLAT, }, 'assistant', ), - ); + ]); const res = (await Promise.race([ props.sendMessageRequest?.(chatListRef.current), new Promise((_, reject) => { - controller.current.signal.addEventListener('abort', () => { + controller.current?.signal.addEventListener('abort', () => { reject(); }); }), @@ -233,75 +221,61 @@ export const useChatList = (props: ProChatUIUseListChatProps) => { processSSE(res, { signal: controller.current.signal, onFinish: async () => { - setLoadingMessage(undefined); + setChatList((prevState) => { + const updatedList = [...prevState]; + updatedList[updatedList.length - 1].isFinished = true; + return updatedList; + }); + setIsLoadingMessage(false); }, onMessageHandle: async (text, res, type) => { - if (type === 'done' || controller.current.signal.aborted) { - const message = getLoadingMessage(); - if (!message) return; - setChatList((prev) => { - message.isFinished = true; - return [...prev, message]; + if (type === 'done' || controller.current?.signal.aborted) { + setIsLoadingMessage(false); + setChatList((prevState) => { + const updatedList = [...prevState]; + updatedList[updatedList.length - 1].isFinished = true; + return updatedList; }); - setLoadingMessage(undefined); return; } - const content = - getLoadingMessage()?.content === LOADING_FLAT - ? text - : getLoadingMessage()?.content + text; - const message: ChatMessage = { - ...getLoadingMessage(), - updateAt: Date.now(), - originContent: text, - isFinished: false, - content: content, - }; - const transformMessage = await props.transformToChatMessage?.(message, { - preContent: - getLoadingMessage()?.content === LOADING_FLAT ? '' : getLoadingMessage()?.content, - currentContent: text, + setChatList((prevState) => { + const updatedList = [...prevState]; + const currentMessage = updatedList[updatedList.length - 1]; + currentMessage.content = + currentMessage.content === LOADING_FLAT ? text : currentMessage.content + text; + currentMessage.updateAt = Date.now(); + return updatedList; }); - - loadingMessageRef.current = transformMessage || message; - setLoadingMessage(transformMessage || message); }, onErrorHandle: async (error) => { const content = error.message; - const message = await props.transformToChatMessage?.( - { - ...getLoadingMessage(), - updateAt: Date.now(), - content: content, - originContent: content, - }, - { - preContent: getLoadingMessage()?.content, - currentContent: content, - }, - ); - setLoadingMessage(undefined); - setChatList((prev) => [...prev, message]); + setChatList((prevState) => { + const updatedList = [...prevState]; + const currentMessage = updatedList[updatedList.length - 1]; + currentMessage.content = content; + currentMessage.originContent = content; + currentMessage.updateAt = Date.now(); + currentMessage.isFinished = true; + return updatedList; + }); + setIsLoadingMessage(false); }, }); } else { - const message = { - ...getLoadingMessage(), - updateAt: Date.now(), - ...res, - }; - - const transformChatMessage = await props.transformToChatMessage?.(message, { - preContent: getLoadingMessage()?.content, - currentContent: message.originContent, + setChatList((prevState) => { + const updatedList = [...prevState]; + const currentMessage = { + ...updatedList[updatedList.length - 1], + ...res, + updateAt: Date.now(), + }; + updatedList[updatedList.length - 1] = currentMessage; + return updatedList; }); - - setLoadingMessage(undefined); - setChatList((prev) => [...prev, transformChatMessage || message]); + setIsLoadingMessage(false); } }); - /** * Stops the generation of messages. */ @@ -330,7 +304,7 @@ export const useChatList = (props: ProChatUIUseListChatProps) => { return { chatList: chatList.length > 0 ? chatList : helloMessageList, loading, - loadingMessage, + isLoadingMessage, stopGenerateMessage, setMessageItem, clearMessage,