Unverified 提交 fd27826e authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Fix scroll behavior when switching between chats (#2643)

## Summary - Fix scroll behavior when switching between chats with existing messages - Use double `requestAnimationFrame` to wait for Virtuoso to render before scrolling to bottom when switching chats - Distinguish between chat switches and new message sends to handle scrolling appropriately - Avoid premature scrolling when switching to chats where messages haven't been fetched yet ## Test plan 1. Open Dyad and start a chat with some messages 2. Start another chat with messages 3. Switch between chats and verify scroll position stays at the bottom 4. Send a new message and verify it scrolls to show the new message 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2643" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes chat auto-scroll to keep the view anchored at the bottom when switching chats or sending messages. Prevents flicker and jumps before messages render. - **Bug Fixes** - Distinguish chat switches vs new sends; adjust scroll timing accordingly. - On chat switch with existing messages, wait for Virtuoso to render (double requestAnimationFrame), then scroll to bottom instantly. - On new message send, wait for the placeholder to render (double requestAnimationFrame) before scrolling; skip auto-scroll when switching to a chat with no messages yet. <sup>Written for commit 8814a601a9615b60efbfbff0aff5b7150a75fa63. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Scoped to `ChatPanel` scroll timing logic; risk is limited to possible UI regressions (missed/extra scroll) when switching chats or starting streams. > > **Overview** > Fixes `ChatPanel` auto-scroll behavior by **distinguishing chat switches from new stream starts** and delaying the scroll until after Virtuoso has rendered. > > On chat switch, it now scrolls to bottom *only after messages exist* (avoiding premature scroll before fetch/render) and uses a double `requestAnimationFrame` with `instant` scrolling; on new message sends (`streamCount` changes), it similarly waits for render before scrolling with the default behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8814a601a9615b60efbfbff0aff5b7150a75fa63. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com>
上级 d1a607f8
......@@ -79,11 +79,38 @@ export function ChatPanel({
// Scroll to bottom when a new stream starts (user sent a message)
const streamCount = chatId ? (streamCountById.get(chatId) ?? 0) : 0;
const messages = chatId ? (messagesById.get(chatId) ?? []) : [];
// Track previous chatId to detect chat switches
const prevChatIdRef = useRef<number | undefined>(undefined);
useEffect(() => {
const isChatSwitch = prevChatIdRef.current !== chatId;
prevChatIdRef.current = chatId;
isAtBottomRef.current = true;
setShowScrollButton(false);
scrollToBottom();
}, [chatId, streamCount, scrollToBottom]);
if (isChatSwitch && messages.length > 0) {
// When switching chats with existing messages, wait for Virtuoso to render
// then scroll to ensure we're at the bottom
requestAnimationFrame(() => {
requestAnimationFrame(() => {
scrollToBottom("instant");
});
});
} else if (!isChatSwitch) {
// For stream count changes (new message sent), wait for Virtuoso to render
// the placeholder message before scrolling
requestAnimationFrame(() => {
requestAnimationFrame(() => {
scrollToBottom();
});
});
}
// Note: if isChatSwitch && messages.length === 0, we don't scroll yet.
// The messages will be fetched and this effect will re-run with messages.length > 0.
}, [chatId, streamCount, messages.length, scrollToBottom]);
const fetchChatMessages = useCallback(async () => {
if (!chatId) {
......@@ -102,7 +129,6 @@ export function ChatPanel({
fetchChatMessages();
}, [fetchChatMessages]);
const messages = chatId ? (messagesById.get(chatId) ?? []) : [];
const isStreaming = chatId ? (isStreamingById.get(chatId) ?? false) : false;
// Scroll to bottom when streaming completes to ensure footer content is visible,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论