我想对我的聊天实现分页,因此当用户向上滚动时,会加载更多消息。目前我面临一个问题,当我向上滚动时,会加载更多消息,但“视图”会捕捉到 FlatList 的顶部,并且它只会加载更多消息,因为它认为用户滚动到了那里。加载新消息时,我无法使视图保持原样。
最初加载 15 条消息,向上滚动时,还会加载 15 条消息并添加到聊天中。
代码:
const Chat = ({ route }) => {
const { user } = useContext(UserContext)
const navigation = useNavigation()
const { conversationId, friend: initialFriend } = route.params
const flatListRef = useRef(null)
const [isAtBottom, setIsAtBottom] = useState(true)
const [isLoadingMore, setIsLoadingMore] = useState(false)
const {
friend, conversation, newMessage,
setNewMessage, inputHeight, setInputHeight,
loading, sendMessage, loadMoreMessages
} = useChat(user, conversationId, initialFriend)
const handleLoadMoreMessages = () => {
if (loading || isAtBottom || isLoadingMore) return
setIsLoadingMore(true)
setTimeout(() => {
loadMoreMessages()
setIsLoadingMore(false)
}, 300)
}
if (loading) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
)
}
return (
<ImageBackground source={defaultBackgroundPicture} style={styles.container}>
<CustomNavBar navigation={navigation} friend={friend}/>
<View style={styles.content}>
<View style={styles.header}>
</View>
{conversation && <FlatList
ref={flatListRef}
key={conversationId}
data={conversation.messages}
keyExtractor={item => item && item._id ? item._id : uuid.v4()}
renderItem={({ item }) => <MessageItem item={item} user={user} />}
onScroll={({ nativeEvent }) => {
const isCloseToBottom = nativeEvent.layoutMeasurement.height + nativeEvent.contentOffset.y >= nativeEvent.contentSize.height - 50
setIsAtBottom(isCloseToBottom)
if (nativeEvent.contentOffset.y < 20) {
handleLoadMoreMessages()
}
}}
onContentSizeChange={() => {
if (isAtBottom) flatListRef.current.scrollToEnd({ animated: false })
}}
/>}
<View style={styles.inputContainer}>
<TextInput
style={[styles.input, { height: Math.max(35, inputHeight) }]}
value={newMessage}
onChangeText={text => setNewMessage(text)}
placeholder="Type a message..."
multiline
onContentSizeChange={(event) => {
setInputHeight(event.nativeEvent.contentSize.height)
}}
/>
<Pressable style={styles.sendButton} onPress={() => {
if (newMessage.length !== 0) sendMessage()
}}>
<Icon name="send" size={24} color="white" />
</Pressable>
</View>
</View>
</ImageBackground>
)
}
我一直在尝试使用平面列表的 onScroll 和 onContentSizeChange 属性。
我通过将数据获取逻辑切换为使用react-query并在FlatList中使用inverted和onEndReached属性来解决这个问题。
<FlatList
inverted
ref={flatListRef}
data={messagesData.pages.flatMap(page => {
return page.conversation.messages
})}
keyExtractor={item => item && item._id ? item._id : uuid.v4()}
renderItem={({ item }) => <MessageItem item={item} user={user} />}
onEndReached={handleEndReached}
onEndReachedTreshold={0.5}
/>