Matthias Nott
2026-03-07 7d69229cd76447b92ee66f472f760994d00817ae
components/chat/MessageList.tsx
....@@ -18,17 +18,17 @@
1818 // Track the last message's content so transcript reflections trigger a scroll
1919 const lastContent = messages.length > 0 ? messages[messages.length - 1].content : "";
2020
21
+ // Flag: when true, every content size change triggers a scroll to bottom.
22
+ // Used for bulk loads (restart, session switch) where FlatList renders lazily.
23
+ const bulkScrollRef = useRef(false);
24
+
2125 useEffect(() => {
2226 if (messages.length > 0) {
2327 const delta = Math.abs(messages.length - prevLengthRef.current);
2428 if (delta > 1) {
25
- // Bulk load (restart, session switch) — FlatList renders lazily,
26
- // so fire multiple scroll attempts to catch late renders.
27
- for (const delay of [100, 300, 700]) {
28
- setTimeout(() => {
29
- listRef.current?.scrollToEnd({ animated: false });
30
- }, delay);
31
- }
29
+ // Bulk load — let onContentSizeChange handle scrolling
30
+ bulkScrollRef.current = true;
31
+ setTimeout(() => { bulkScrollRef.current = false; }, 3000);
3232 } else {
3333 // Single new message — smooth scroll
3434 setTimeout(() => {
....@@ -38,6 +38,12 @@
3838 }
3939 prevLengthRef.current = messages.length;
4040 }, [messages.length, isTyping, lastContent]);
41
+
42
+ const handleContentSizeChange = useCallback(() => {
43
+ if (bulkScrollRef.current) {
44
+ listRef.current?.scrollToEnd({ animated: false });
45
+ }
46
+ }, []);
4147
4248 // Play from a voice message and auto-chain all consecutive assistant voice messages after it
4349 const handlePlayVoice = useCallback(async (messageId: string) => {
....@@ -77,6 +83,7 @@
7783 onPlayVoice={handlePlayVoice}
7884 />
7985 )}
86
+ onContentSizeChange={handleContentSizeChange}
8087 contentContainerStyle={{ paddingVertical: 12 }}
8188 showsVerticalScrollIndicator={false}
8289 ListFooterComponent={