From 5df6ae35cc08f220d5eb65d2ed28c168365b1df2 Mon Sep 17 00:00:00 2001 From: c-d-p Date: Mon, 21 Apr 2025 20:25:16 +0200 Subject: [PATCH] quick fix to autoscroll on chat window --- .../nativeapp/src/screens/ChatScreen.tsx | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/interfaces/nativeapp/src/screens/ChatScreen.tsx b/interfaces/nativeapp/src/screens/ChatScreen.tsx index 7d179c0..8e1020b 100644 --- a/interfaces/nativeapp/src/screens/ChatScreen.tsx +++ b/interfaces/nativeapp/src/screens/ChatScreen.tsx @@ -72,10 +72,6 @@ const ChatScreen = () => { // Add user message optimistically setMessages(prevMessages => [...prevMessages, userMessage]); setIsLoading(true); - - // Scroll to bottom after adding user message - setTimeout(() => flatListRef.current?.scrollToEnd({ animated: true }), 100); - // --- Call Backend API --- try { console.log(`[ChatScreen] Sending to /nlp/process-command: ${textToSend}`); @@ -116,14 +112,9 @@ const ChatScreen = () => { setMessages(prevMessages => [...prevMessages, errorResponse]); } finally { setIsLoading(false); - // Scroll to bottom after receiving AI message(s) - setTimeout(() => flatListRef.current?.scrollToEnd({ animated: true }), 100); } // --- End API Call --- - // NOTE: Removed `messages` from dependency array to prevent potential loops. - // State updates within useCallback using the functional form `setMessages(prev => ...)` - // don't require the state itself as a dependency. - }, []); + }, []); // Dependencies are correct // --- Load messages from backend API on mount & handle initial question --- useEffect(() => { @@ -146,6 +137,8 @@ const ChatScreen = () => { })); setMessages(historyMessages); historyLoadedSuccessfully = true; // Mark history as loaded + // ADDED BACK: Scroll after initial history is set, with a delay + setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 100); } else { console.warn("[ChatScreen] Received invalid history data:", response.data); setMessages([]); @@ -163,15 +156,18 @@ const ChatScreen = () => { // Send initial question *after* history load attempt, if provided if (initialQuestion) { console.log("[ChatScreen] Initial question provided:", initialQuestion); - // Check if the initial question is already the last message from history (simple check) - const lastMessageText = messages[messages.length - 1]?.text; - if (lastMessageText !== initialQuestion) { - console.log("[ChatScreen] Sending initial question now."); - // Use a timeout to ensure history state update is processed before sending - setTimeout(() => sendMessageToApi(initialQuestion), 0); - } else { - console.log("[ChatScreen] Initial question seems to match last history message, not sending again."); - } + // Use functional update form of setMessages to get the latest state + setMessages(currentMessages => { + const lastMessageText = currentMessages[currentMessages.length - 1]?.text; + if (lastMessageText !== initialQuestion) { + console.log("[ChatScreen] Sending initial question now."); + // Use a timeout to ensure history state update is processed before sending + setTimeout(() => sendMessageToApi(initialQuestion), 0); + } else { + console.log("[ChatScreen] Initial question seems to match last history message, not sending again."); + } + return currentMessages; // Return the state unchanged if not sending + }); } else { console.log("[ChatScreen] No initial question provided."); } @@ -185,8 +181,7 @@ const ChatScreen = () => { isMounted = false; // Cleanup function to set flag on unmount console.log("[ChatScreen] Component unmounted."); }; - // Run only once on mount. `initialQuestion` is stable after mount. - // `sendMessageToApi` is memoized by useCallback. + // Dependencies are correct // eslint-disable-next-line react-hooks/exhaustive-deps }, [initialQuestion, sendMessageToApi]); @@ -314,10 +309,8 @@ const ChatScreen = () => { renderItem={renderMessage} keyExtractor={(item) => item.id} contentContainerStyle={styles.messageList} - // Optimization: remove onContentSizeChange/onLayout if not strictly needed for scrolling - // onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: false })} - // onLayout={() => flatListRef.current?.scrollToEnd({ animated: false })} - // Consider initialScrollIndex or other props if performance is an issue + // ADDED: Scroll to end when content size changes + onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: false })} />