| .. | .. |
|---|
| 20 | 20 | |
|---|
| 21 | 21 | useEffect(() => { |
|---|
| 22 | 22 | if (messages.length > 0) { |
|---|
| 23 | | - // If the message count changed by more than 1, it's a session switch or |
|---|
| 24 | | - // initial load — snap to bottom instantly instead of visibly scrolling. |
|---|
| 25 | 23 | const delta = Math.abs(messages.length - prevLengthRef.current); |
|---|
| 26 | | - const animated = delta === 1; |
|---|
| 27 | | - const delay = delta > 1 ? 200 : 50; |
|---|
| 28 | | - setTimeout(() => { |
|---|
| 29 | | - listRef.current?.scrollToEnd({ animated }); |
|---|
| 30 | | - }, delay); |
|---|
| 24 | + 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 | + } |
|---|
| 32 | + } else { |
|---|
| 33 | + // Single new message — smooth scroll |
|---|
| 34 | + setTimeout(() => { |
|---|
| 35 | + listRef.current?.scrollToEnd({ animated: true }); |
|---|
| 36 | + }, 50); |
|---|
| 37 | + } |
|---|
| 31 | 38 | } |
|---|
| 32 | 39 | prevLengthRef.current = messages.length; |
|---|
| 33 | 40 | }, [messages.length, isTyping, lastContent]); |
|---|