fix
This commit is contained in:
parent
6ac3f69e24
commit
918f4da40e
@ -21,8 +21,7 @@ import {
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
||||
import { runOnJS, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
||||
import { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
||||
export default function AskScreen() {
|
||||
@ -30,6 +29,11 @@ export default function AskScreen() {
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const chatListRef = useRef<FlatList>(null);
|
||||
const isMountedRef = useRef(true);
|
||||
const scrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const keyboardTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
const [isHello, setIsHello] = useState(true);
|
||||
const [conversationId, setConversationId] = useState<string | null>(null);
|
||||
const [userMessages, setUserMessages] = useState<Message[]>([]);
|
||||
@ -43,29 +47,49 @@ export default function AskScreen() {
|
||||
newSession: string;
|
||||
}>();
|
||||
|
||||
// 创建一个可复用的滚动函数
|
||||
// 创建一个安全的滚动函数
|
||||
const scrollToEnd = useCallback((animated = true) => {
|
||||
if (chatListRef.current) {
|
||||
setTimeout(() => chatListRef.current?.scrollToEnd({ animated }), 100);
|
||||
if (!isMountedRef.current || !chatListRef.current) return;
|
||||
|
||||
// 清理之前的定时器
|
||||
if (scrollTimeoutRef.current) {
|
||||
clearTimeout(scrollTimeoutRef.current);
|
||||
}
|
||||
|
||||
scrollTimeoutRef.current = setTimeout(() => {
|
||||
if (isMountedRef.current && chatListRef.current) {
|
||||
try {
|
||||
chatListRef.current.scrollToEnd({ animated });
|
||||
} catch (error) {
|
||||
console.warn('滚动到底部失败:', error);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}, []);
|
||||
|
||||
// 清理函数
|
||||
const cleanup = useCallback(() => {
|
||||
isMountedRef.current = false;
|
||||
|
||||
// 清理定时器
|
||||
if (scrollTimeoutRef.current) {
|
||||
clearTimeout(scrollTimeoutRef.current);
|
||||
scrollTimeoutRef.current = null;
|
||||
}
|
||||
if (keyboardTimeoutRef.current) {
|
||||
clearTimeout(keyboardTimeoutRef.current);
|
||||
keyboardTimeoutRef.current = null;
|
||||
}
|
||||
|
||||
// 取消API请求
|
||||
if (abortControllerRef.current) {
|
||||
abortControllerRef.current.abort();
|
||||
abortControllerRef.current = null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 右滑
|
||||
const gesture = Gesture.Pan()
|
||||
.onEnd((event) => {
|
||||
const { translationX } = event;
|
||||
const threshold = 100; // 滑动阈值
|
||||
|
||||
if (translationX > threshold) {
|
||||
// 从左向右滑动,跳转页面
|
||||
runOnJS(router.replace)("/memo-list");
|
||||
}
|
||||
})
|
||||
.minPointers(1)
|
||||
.activeOffsetX([-10, 10]); // 在 X 方向触发的范围
|
||||
|
||||
useEffect(() => {
|
||||
if (!isHello && userMessages.length > 0) {
|
||||
if (!isHello && userMessages.length > 0 && isMountedRef.current) {
|
||||
scrollToEnd();
|
||||
}
|
||||
}, [userMessages, isHello, scrollToEnd]);
|
||||
@ -74,8 +98,12 @@ export default function AskScreen() {
|
||||
const keyboardDidShowListener = Keyboard.addListener(
|
||||
'keyboardDidShow',
|
||||
(e) => {
|
||||
setTimeout(() => {
|
||||
if (!isHello) {
|
||||
if (keyboardTimeoutRef.current) {
|
||||
clearTimeout(keyboardTimeoutRef.current);
|
||||
}
|
||||
|
||||
keyboardTimeoutRef.current = setTimeout(() => {
|
||||
if (isMountedRef.current && !isHello) {
|
||||
scrollToEnd();
|
||||
}
|
||||
}, 100);
|
||||
@ -85,8 +113,12 @@ export default function AskScreen() {
|
||||
const keyboardDidHideListener = Keyboard.addListener(
|
||||
'keyboardDidHide',
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
if (!isHello) {
|
||||
if (keyboardTimeoutRef.current) {
|
||||
clearTimeout(keyboardTimeoutRef.current);
|
||||
}
|
||||
|
||||
keyboardTimeoutRef.current = setTimeout(() => {
|
||||
if (isMountedRef.current && !isHello) {
|
||||
scrollToEnd(false);
|
||||
}
|
||||
}, 100);
|
||||
@ -96,27 +128,29 @@ export default function AskScreen() {
|
||||
return () => {
|
||||
keyboardDidShowListener.remove();
|
||||
keyboardDidHideListener.remove();
|
||||
if (keyboardTimeoutRef.current) {
|
||||
clearTimeout(keyboardTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, [isHello]);
|
||||
}, [isHello, scrollToEnd]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
let isMounted = true;
|
||||
isMountedRef.current = true;
|
||||
|
||||
// 使用新的WebSocket订阅hook
|
||||
const { subscribeToWebSocket } = useWebSocketSubscription(setUserMessages, isMounted);
|
||||
const { subscribeToWebSocket } = useWebSocketSubscription(setUserMessages, isMountedRef.current);
|
||||
|
||||
// 订阅WebSocket消息
|
||||
const unsubscribe = subscribeToWebSocket();
|
||||
|
||||
return () => {
|
||||
// 设置组件卸载标志
|
||||
isMounted = false;
|
||||
|
||||
// 取消订阅
|
||||
unsubscribe();
|
||||
// 执行清理
|
||||
cleanup();
|
||||
};
|
||||
}, [t])
|
||||
}, [t, cleanup])
|
||||
);
|
||||
|
||||
// 创建动画样式
|
||||
@ -141,39 +175,50 @@ export default function AskScreen() {
|
||||
}, [isHello]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sessionId) {
|
||||
if (sessionId && isMountedRef.current) {
|
||||
setConversationId(sessionId);
|
||||
setIsHello(false);
|
||||
fetchApi<Message[]>(`/chats/${sessionId}/message-history`).then((res) => {
|
||||
setUserMessages(res);
|
||||
|
||||
// 创建新的AbortController
|
||||
abortControllerRef.current = new AbortController();
|
||||
|
||||
fetchApi<Message[]>(`/chats/${sessionId}/message-history`, {
|
||||
signal: abortControllerRef.current.signal
|
||||
}).then((res) => {
|
||||
if (isMountedRef.current) {
|
||||
setUserMessages(res);
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error.name !== 'AbortError') {
|
||||
console.error('获取消息历史失败:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (newSession) {
|
||||
if (newSession && isMountedRef.current) {
|
||||
setIsHello(true);
|
||||
setConversationId(null);
|
||||
}
|
||||
}, [sessionId, newSession]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isHello) {
|
||||
if (!isHello && isMountedRef.current) {
|
||||
// 不再自动关闭键盘,让用户手动控制
|
||||
// 这里可以添加其他需要在隐藏hello界面时执行的逻辑
|
||||
scrollToEnd(false);
|
||||
}
|
||||
}, [isHello]);
|
||||
}, [isHello, scrollToEnd]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!sessionId) {
|
||||
if (!sessionId && isMountedRef.current) {
|
||||
setIsHello(true);
|
||||
setUserMessages([])
|
||||
setUserMessages([]);
|
||||
}
|
||||
}, [sessionId])
|
||||
);
|
||||
|
||||
return (
|
||||
<GestureDetector gesture={gesture}>
|
||||
<View style={[styles.container, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
|
||||
<View style={[styles.container, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
|
||||
{/* 导航栏 */}
|
||||
<View style={[styles.navbar, isHello && styles.hiddenNavbar]}>
|
||||
<TouchableOpacity
|
||||
@ -238,8 +283,7 @@ export default function AskScreen() {
|
||||
/>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</View >
|
||||
</GestureDetector >
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -31,39 +31,67 @@ const RENDER_INTERVAL = 50; // 渲染间隔,单位毫秒
|
||||
export default function SendMessage(props: Props) {
|
||||
const { setIsHello, conversationId, setUserMessages, setConversationId, selectedImages, setSelectedImages } = props;
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { t } = useTranslation();
|
||||
|
||||
// 用户询问
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
// 添加一个ref来跟踪键盘状态
|
||||
// 添加组件挂载状态跟踪
|
||||
const isMountedRef = useRef(true);
|
||||
const isKeyboardVisible = useRef(false);
|
||||
const chunkQueue = useRef<string[]>([]);
|
||||
const renderInterval = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
// 清理函数
|
||||
const cleanup = useCallback(() => {
|
||||
isMountedRef.current = false;
|
||||
|
||||
// 清理定时器
|
||||
if (renderInterval.current) {
|
||||
clearInterval(renderInterval.current);
|
||||
renderInterval.current = null;
|
||||
}
|
||||
|
||||
// 清理队列
|
||||
chunkQueue.current = [];
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleChatStream = (message: WsMessage) => {
|
||||
if (message.type !== 'ChatStream' || !message.chunk) return;
|
||||
if (!isMountedRef.current || message.type !== 'ChatStream' || !message.chunk) return;
|
||||
|
||||
chunkQueue.current.push(message.chunk);
|
||||
|
||||
if (!renderInterval.current) {
|
||||
renderInterval.current = setInterval(() => {
|
||||
if (!isMountedRef.current) {
|
||||
if (renderInterval.current) {
|
||||
clearInterval(renderInterval.current);
|
||||
renderInterval.current = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunkQueue.current.length > 0) {
|
||||
const textToRender = chunkQueue.current.join('');
|
||||
chunkQueue.current = [];
|
||||
|
||||
setUserMessages(prevMessages => {
|
||||
if (prevMessages.length === 0) return prevMessages;
|
||||
try {
|
||||
if (prevMessages.length === 0) return prevMessages;
|
||||
|
||||
const lastMessage = prevMessages[prevMessages.length - 1];
|
||||
if (lastMessage.role !== 'assistant') return prevMessages;
|
||||
const lastMessage = prevMessages[prevMessages.length - 1];
|
||||
if (lastMessage.role !== 'assistant') return prevMessages;
|
||||
|
||||
const updatedContent = (lastMessage.content === 'keepSearchIng' ? '' : lastMessage.content) + textToRender;
|
||||
const updatedContent = (lastMessage.content === 'keepSearchIng' ? '' : lastMessage.content) + textToRender;
|
||||
|
||||
const updatedLastMessage = { ...lastMessage, content: updatedContent };
|
||||
const updatedLastMessage = { ...lastMessage, content: updatedContent };
|
||||
|
||||
return [...prevMessages.slice(0, -1), updatedLastMessage];
|
||||
return [...prevMessages.slice(0, -1), updatedLastMessage];
|
||||
} catch (error) {
|
||||
console.error('处理流式消息时出错:', error);
|
||||
return prevMessages;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (renderInterval.current) {
|
||||
@ -76,7 +104,7 @@ export default function SendMessage(props: Props) {
|
||||
};
|
||||
|
||||
const handleChatStreamEnd = (message: WsMessage) => {
|
||||
if (message.type !== 'ChatStreamEnd') return;
|
||||
if (!isMountedRef.current || message.type !== 'ChatStreamEnd') return;
|
||||
|
||||
// Stop the timer and process any remaining chunks
|
||||
if (renderInterval.current) {
|
||||
@ -88,37 +116,47 @@ export default function SendMessage(props: Props) {
|
||||
chunkQueue.current = [];
|
||||
|
||||
setUserMessages(prevMessages => {
|
||||
if (prevMessages.length === 0) return prevMessages;
|
||||
try {
|
||||
if (prevMessages.length === 0) return prevMessages;
|
||||
|
||||
const lastMessage = prevMessages[prevMessages.length - 1];
|
||||
if (lastMessage.role !== 'assistant') return prevMessages;
|
||||
const lastMessage = prevMessages[prevMessages.length - 1];
|
||||
if (lastMessage.role !== 'assistant') return prevMessages;
|
||||
|
||||
// Apply remaining chunks from the queue
|
||||
const contentWithQueue = (lastMessage.content === 'keepSearchIng' ? '' : lastMessage.content) + remainingText;
|
||||
// Apply remaining chunks from the queue
|
||||
const contentWithQueue = (lastMessage.content === 'keepSearchIng' ? '' : lastMessage.content) + remainingText;
|
||||
|
||||
// Create the final updated message object
|
||||
const updatedLastMessage = {
|
||||
...lastMessage,
|
||||
// Use the final message from ChatStreamEnd if available, otherwise use the content with queued text
|
||||
content: message.message ? message.message.content : contentWithQueue,
|
||||
timestamp: message.message ? message.message.timestamp : lastMessage.timestamp,
|
||||
};
|
||||
// Create the final updated message object
|
||||
const updatedLastMessage = {
|
||||
...lastMessage,
|
||||
// Use the final message from ChatStreamEnd if available, otherwise use the content with queued text
|
||||
content: message.message ? message.message.content : contentWithQueue,
|
||||
timestamp: message.message ? message.message.timestamp : lastMessage.timestamp,
|
||||
};
|
||||
|
||||
return [...prevMessages.slice(0, -1), updatedLastMessage];
|
||||
return [...prevMessages.slice(0, -1), updatedLastMessage];
|
||||
} catch (error) {
|
||||
console.error('处理ChatStreamEnd消息时出错:', error);
|
||||
return prevMessages;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleChatResponse = (message: WsMessage) => {
|
||||
if (message.type === 'ChatResponse' && message.message) {
|
||||
setUserMessages(prev => {
|
||||
const newMessages = prev.filter(item => item.content !== 'keepSearchIng');
|
||||
return [...newMessages, {
|
||||
...(message.message as Message),
|
||||
role: 'assistant',
|
||||
}];
|
||||
if (!isMountedRef.current || message.type !== 'ChatResponse') return;
|
||||
|
||||
if (message.message) {
|
||||
setUserMessages(prevMessages => {
|
||||
try {
|
||||
const updatedMessages = [...prevMessages];
|
||||
updatedMessages[updatedMessages.length - 1] = message.message as Message;
|
||||
return updatedMessages;
|
||||
} catch (error) {
|
||||
console.error('处理聊天响应时出错:', error);
|
||||
return prevMessages;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const typedHandleChatStream = handleChatStream as (message: WsMessage) => void;
|
||||
const typedHandleChatStreamEnd = handleChatStreamEnd as (message: WsMessage) => void;
|
||||
@ -130,14 +168,21 @@ export default function SendMessage(props: Props) {
|
||||
webSocketManager.subscribe('ChatResponse', typedHandleChatResponse);
|
||||
|
||||
return () => {
|
||||
webSocketManager.unsubscribe('ChatStream', typedHandleChatStream);
|
||||
webSocketManager.unsubscribe('ChatStreamEnd', typedHandleChatStreamEnd);
|
||||
webSocketManager.unsubscribe('ChatResponse', typedHandleChatResponse);
|
||||
if (renderInterval.current) {
|
||||
clearInterval(renderInterval.current);
|
||||
}
|
||||
webSocketManager.unsubscribe('ChatStream', handleChatStream);
|
||||
webSocketManager.unsubscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
webSocketManager.unsubscribe('ChatResponse', handleChatResponse);
|
||||
|
||||
// 执行清理
|
||||
cleanup();
|
||||
};
|
||||
}, [setUserMessages]);
|
||||
}, [setUserMessages, cleanup]);
|
||||
|
||||
// 组件卸载时的清理
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
useEffect(() => {
|
||||
// 使用keyboardWillShow而不是keyboardDidShow,这样可以在键盘完全显示前更新UI
|
||||
@ -172,11 +217,15 @@ export default function SendMessage(props: Props) {
|
||||
|
||||
// 发送询问
|
||||
const handleSubmit = useCallback(async () => {
|
||||
if (!inputValue.trim() || !isMountedRef.current) return;
|
||||
|
||||
const text = inputValue.trim();
|
||||
// 用户输入信息之后进行后续操作
|
||||
if (text) {
|
||||
// 将用户输入信息添加到消息列表中
|
||||
setUserMessages(pre => ([...pre, {
|
||||
setIsHello(false);
|
||||
|
||||
// 添加用户消息和占位符助手消息
|
||||
setUserMessages(prev => [
|
||||
...prev,
|
||||
{
|
||||
id: Math.random().toString(36).substring(2, 9),
|
||||
content: text,
|
||||
role: 'user',
|
||||
@ -188,24 +237,18 @@ export default function SendMessage(props: Props) {
|
||||
role: 'assistant',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
]));
|
||||
]);
|
||||
|
||||
try {
|
||||
let currentSessionId = conversationId;
|
||||
// 如果没有对话ID,先创建一个新对话
|
||||
if (!currentSessionId) {
|
||||
currentSessionId = await createNewConversation(text);
|
||||
setConversationId(currentSessionId);
|
||||
const webSocketManager = getWebSocketManager();
|
||||
webSocketManager.send({
|
||||
type: 'Chat',
|
||||
session_id: currentSessionId,
|
||||
message: text,
|
||||
image_material_ids: selectedImages.length > 0 ? selectedImages : undefined,
|
||||
});
|
||||
setSelectedImages([]);
|
||||
if (currentSessionId && isMountedRef.current) {
|
||||
setConversationId(currentSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
// 通过 WebSocket 发送消息
|
||||
if (currentSessionId) {
|
||||
if (currentSessionId && isMountedRef.current) {
|
||||
const webSocketManager = getWebSocketManager();
|
||||
webSocketManager.send({
|
||||
type: 'Chat',
|
||||
@ -217,9 +260,19 @@ export default function SendMessage(props: Props) {
|
||||
} else {
|
||||
console.error("无法获取 session_id,消息发送失败。");
|
||||
// 可以在这里处理错误,例如显示一个提示
|
||||
if (isMountedRef.current) {
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送消息时出错:', error);
|
||||
if (isMountedRef.current) {
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
}
|
||||
// 将输入框清空
|
||||
}
|
||||
|
||||
// 将输入框清空
|
||||
if (isMountedRef.current) {
|
||||
setInputValue('');
|
||||
// 只有在键盘可见时才关闭键盘
|
||||
if (isKeyboardVisible.current) {
|
||||
@ -228,8 +281,10 @@ export default function SendMessage(props: Props) {
|
||||
}
|
||||
}, [inputValue, conversationId, selectedImages, createNewConversation, setConversationId, setSelectedImages, setUserMessages]);
|
||||
|
||||
const handleQuitly = (type: string) => {
|
||||
setIsHello(false)
|
||||
const handleQuitly = useCallback((type: string) => {
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
setIsHello(false);
|
||||
setUserMessages(pre => ([
|
||||
...pre,
|
||||
{
|
||||
@ -240,8 +295,8 @@ export default function SendMessage(props: Props) {
|
||||
role: 'assistant',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
]))
|
||||
};
|
||||
]));
|
||||
}, [t, setIsHello, setUserMessages]);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getWebSocketManager, WsMessage, getWebSocketErrorMessage } from '@/lib/websocket-util';
|
||||
import { Message, Assistant } from '@/types/ask';
|
||||
@ -9,10 +9,16 @@ export const useWebSocketSubscription = (
|
||||
isMounted: boolean
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const isMountedRef = useRef(isMounted);
|
||||
|
||||
// 更新挂载状态
|
||||
useEffect(() => {
|
||||
isMountedRef.current = isMounted;
|
||||
}, [isMounted]);
|
||||
|
||||
const handleChatStream = useCallback((message: WsMessage) => {
|
||||
// 确保组件仍然挂载
|
||||
if (!isMounted) return;
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
if (message.type === 'ChatStream') {
|
||||
setUserMessages(prevMessages => {
|
||||
@ -71,7 +77,7 @@ export const useWebSocketSubscription = (
|
||||
|
||||
const handleChatStreamEnd = useCallback((message: WsMessage) => {
|
||||
// 确保组件仍然挂载
|
||||
if (!isMounted) return;
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
if (message.type === 'ChatStreamEnd') {
|
||||
setUserMessages(prevMessages => {
|
||||
@ -106,7 +112,7 @@ export const useWebSocketSubscription = (
|
||||
|
||||
const handleError = useCallback((message: WsMessage) => {
|
||||
// 确保组件仍然挂载
|
||||
if (!isMounted) return;
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
if (message.type === 'Error') {
|
||||
console.log(`WebSocket Error: ${message.code} - ${message.message}`);
|
||||
@ -139,7 +145,7 @@ export const useWebSocketSubscription = (
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [setUserMessages, isMounted, t]);
|
||||
}, [setUserMessages, t]);
|
||||
|
||||
const subscribeToWebSocket = useCallback(() => {
|
||||
const webSocketManager = getWebSocketManager();
|
||||
@ -155,8 +161,8 @@ export const useWebSocketSubscription = (
|
||||
webSocketManager.unsubscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
webSocketManager.unsubscribe('Error', handleError);
|
||||
|
||||
// 可以在这里选择断开连接,或者保持连接以加快下次进入页面的速度
|
||||
webSocketManager.disconnect();
|
||||
// 不要在这里断开连接,因为其他组件可能还在使用
|
||||
// webSocketManager.disconnect();
|
||||
};
|
||||
}, [handleChatStream, handleChatStreamEnd, handleError]);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user