From 8d33294cc562c374f49975824b953df7ee695172 Mon Sep 17 00:00:00 2001 From: Nikolas Syring Date: Sat, 20 Dec 2025 17:44:46 +0100 Subject: [PATCH] fix: Reset scroll state when switching between split/tabbed view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Back to bottom" button was incorrectly appearing after switching from split view to tabbed view because scroll-related refs weren't being reset when the session changed. Added session change detection that resets: - userScrolledAway ref - showScrollButton state - newMessageCount counter - processedMessages cache 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- frontend/src/components/MessageList.jsx | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/MessageList.jsx b/frontend/src/components/MessageList.jsx index 6219e1f..d868466 100644 --- a/frontend/src/components/MessageList.jsx +++ b/frontend/src/components/MessageList.jsx @@ -182,6 +182,42 @@ export const MessageList = memo(function MessageList({ messages, isProcessing, o const [newMessageCount, setNewMessageCount] = useState(0); const prevMessageCount = useRef(messages.length); const userScrolledAway = useRef(false); + const prevHostId = useRef(hostId); + + // Cache for incremental updates - avoid full rebuild on streaming content changes + // Moved up so it's available for the reset effect + const processedCacheRef = useRef({ messages: [], result: [], toolResultMap: new Map() }); + + // Reset scroll state when switching sessions (hostId changes or messages array replaced) + // This fixes the "scroll to bottom" button appearing incorrectly after switching from split view + useLayoutEffect(() => { + // Detect session change by checking if hostId changed or if messages were reset + const hostChanged = prevHostId.current !== hostId; + const messagesReset = messages.length === 0 || + (prevMessageCount.current > 0 && messages.length > 0 && + messages[0]?.timestamp !== processedCacheRef.current.messages[0]?.timestamp); + + if (hostChanged || messagesReset) { + // Reset all scroll-related state + userScrolledAway.current = false; + setShowScrollButton(false); + setNewMessageCount(0); + prevMessageCount.current = messages.length; + prevHostId.current = hostId; + + // Clear processed cache to force rebuild + processedCacheRef.current = { messages: [], result: [], toolResultMap: new Map() }; + + // Scroll to bottom after session switch + if (containerRef.current) { + requestAnimationFrame(() => { + if (containerRef.current) { + containerRef.current.scrollTop = containerRef.current.scrollHeight; + } + }); + } + } + }, [hostId, messages]); // Check if scrolled to bottom const checkIfAtBottom = useCallback(() => { @@ -203,9 +239,6 @@ export const MessageList = memo(function MessageList({ messages, isProcessing, o } }, [checkIfAtBottom]); - // Cache for incremental updates - avoid full rebuild on streaming content changes - const processedCacheRef = useRef({ messages: [], result: [], toolResultMap: new Map() }); - // Preprocess messages to pair tool_use with tool_result // Optimized: only rebuild when structure changes, not content const processedMessages = useMemo(() => {