fix: chat starts scrolled to bottom instead of visibly scrolling down
- Use onContentSizeChange to scroll after FlashList renders content - Scroll without animation on initial load via needsInitialScroll ref - Remove unreliable 100ms timeout scrollToEnd from message loading
This commit is contained in:
@@ -634,7 +634,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- Tracks conversationId for message continuity across sessions
|
||||
- ChatStore with addMessages() for bulk loading, chatMessageToMessageData() helper
|
||||
- KeyboardAvoidingView for proper keyboard handling (iOS padding, Android height)
|
||||
- Auto-scroll to end on new messages and keyboard show
|
||||
- Auto-scroll to end on new messages and keyboard show; initial load uses `onContentSizeChange` with `animated: false` to start at bottom without visible scrolling
|
||||
- keyboardDismissMode="interactive" and keyboardShouldPersistTaps="handled"
|
||||
- `EventService`: getAll(), getById(), getByDateRange(), create(), update(), delete(mode, occurrenceDate) - fully implemented with recurring delete modes
|
||||
- `ChatService`: sendMessage(), confirmEvent(deleteMode, occurrenceDate), rejectEvent(), getConversations(), getConversation(), updateProposalEvent() - fully implemented with cursor pagination, recurring delete support, and proposal editing
|
||||
|
||||
@@ -64,11 +64,11 @@ const Chat = () => {
|
||||
string | undefined
|
||||
>();
|
||||
const [hasLoadedMessages, setHasLoadedMessages] = useState(false);
|
||||
const needsInitialScroll = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const keyboardDidShow = Keyboard.addListener(
|
||||
"keyboardDidShow",
|
||||
scrollToEnd,
|
||||
const keyboardDidShow = Keyboard.addListener("keyboardDidShow", () =>
|
||||
scrollToEnd(),
|
||||
);
|
||||
return () => keyboardDidShow.remove();
|
||||
}, []);
|
||||
@@ -90,7 +90,7 @@ const Chat = () => {
|
||||
await ChatService.getConversation(conversationId);
|
||||
const clientMessages = serverMessages.map(chatMessageToMessageData);
|
||||
addMessages(clientMessages);
|
||||
scrollToEnd();
|
||||
needsInitialScroll.current = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load messages:", error);
|
||||
@@ -102,9 +102,9 @@ const Chat = () => {
|
||||
}, [isAuthLoading, isAuthenticated, hasLoadedMessages]),
|
||||
);
|
||||
|
||||
const scrollToEnd = () => {
|
||||
const scrollToEnd = (animated = true) => {
|
||||
setTimeout(() => {
|
||||
listRef.current?.scrollToEnd({ animated: true });
|
||||
listRef.current?.scrollToEnd({ animated });
|
||||
}, 100);
|
||||
};
|
||||
|
||||
@@ -277,6 +277,12 @@ const Chat = () => {
|
||||
keyExtractor={(item) => item.id}
|
||||
keyboardDismissMode="interactive"
|
||||
keyboardShouldPersistTaps="handled"
|
||||
onContentSizeChange={() => {
|
||||
if (needsInitialScroll.current) {
|
||||
needsInitialScroll.current = false;
|
||||
listRef.current?.scrollToEnd({ animated: false });
|
||||
}
|
||||
}}
|
||||
ListFooterComponent={
|
||||
isWaitingForResponse ? <TypingIndicator /> : null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user