Skip to content

Commit d4253b3

Browse files
authored
Scroll to latest on channel switch instead of remounting the scroller
Keying the provider by channelId re-fired the initial end-scroll but rebuilt the entire feed subtree (rows, observers, reply polling) on every switch, making channel changes feel sluggish. Replace the key with a headless LandAtLatestOnChannelChange component that imperatively calls scrollToEnd in a layout effect when the channel id changes — same commit as the swapped rows, before paint, no remount. Generated-By: PostHog Code Task-Id: d887d524-7d87-4d7a-b38c-b20289937ad1
1 parent f6f2bb8 commit d4253b3

1 file changed

Lines changed: 21 additions & 5 deletions

File tree

packages/ui/src/features/canvas/components/ChannelFeedView.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
memo,
6060
type ReactNode,
6161
useEffect,
62+
useLayoutEffect,
6263
useMemo,
6364
useRef,
6465
} from "react";
@@ -628,6 +629,24 @@ function FollowOwnPost({ latestPendingId }: { latestPendingId?: string }) {
628629
return null;
629630
}
630631

632+
// Land at the latest message when the feed swaps to another channel: the route
633+
// doesn't remount on a param change, so the provider's one-shot
634+
// defaultScrollPosition only covers the channel it mounted with. Imperative
635+
// rather than keying the provider — a remount would rebuild the entire feed
636+
// subtree on every switch. Layout effect so the jump happens in the same
637+
// commit as the swapped rows, before paint. Renders nothing.
638+
function LandAtLatestOnChannelChange({ channelId }: { channelId: string }) {
639+
const { scrollToEnd } = useChatMessageScroller();
640+
const prevRef = useRef(channelId);
641+
useLayoutEffect(() => {
642+
if (channelId !== prevRef.current) {
643+
prevRef.current = channelId;
644+
scrollToEnd({ behavior: "auto" });
645+
}
646+
}, [channelId, scrollToEnd]);
647+
return null;
648+
}
649+
631650
// A single feed entry, either a real task card or a synthetic system row, tagged
632651
// with the timestamp used to interleave the two.
633652
type FeedEntry =
@@ -716,11 +735,8 @@ export function ChannelFeedView({
716735
const latestPendingId = pending[pending.length - 1]?.id;
717736

718737
return (
719-
// Keyed by channel: switching channels swaps the content without a route
720-
// remount, but the scroller only applies defaultScrollPosition once per
721-
// mount — an un-keyed provider would keep the previous channel's scroll
722-
// offset instead of landing at the latest message.
723-
<ChatMessageScrollerProvider key={channelId} defaultScrollPosition="end">
738+
<ChatMessageScrollerProvider defaultScrollPosition="end">
739+
<LandAtLatestOnChannelChange channelId={channelId} />
724740
<FollowOwnPost latestPendingId={latestPendingId} />
725741
<ChatMessageScroller className="min-h-0 flex-1">
726742
<ChatMessageScrollerViewport>

0 commit comments

Comments
 (0)