feat(performance): migrate FlatList to FlashList and add animations
Some checks failed
Frontend CI / build-and-push-web (push) Failing after 3m9s
Frontend CI / ota-android (push) Successful in 10m37s
Frontend CI / build-android-apk (push) Has been cancelled

Replace FlatList with FlashList across all message screens (ChatScreen, MessageListScreen, NotificationsScreen, HomeScreen) for improved list virtualization performance. Use `drawDistance={250}` instead of manual pagination. Simplify React.memo comparisons in MessageBubble and SegmentRenderer by removing function prop checks to prevent unnecessary re-renders.

Add AsyncStorage persistence for lastSystemMessageAt to avoid showing current time on first render. Include enter animations (fade and slide) for CreateGroupScreen and modernize UI styling to flat design.

BREAKING CHANGE: Upgrade @shopify/flash-list from 2.0.2 to ^2.3.1
This commit is contained in:
lafay
2026-04-25 15:09:00 +08:00
parent 19054d64b3
commit a6a4198ac5
14 changed files with 746 additions and 680 deletions

View File

@@ -5,10 +5,9 @@
*/
import React, { useRef, useMemo, useCallback } from 'react';
import {
View,
TouchableOpacity,
Image,
import {
View,
TouchableOpacity,
GestureResponderEvent,
StyleSheet,
Dimensions,
@@ -123,8 +122,6 @@ const MessageBubbleInner: React.FC<MessageBubbleProps> = ({
};
});
// 检查当前消息是否被选中
// 获取发送者信息(群聊)- 供子组件使用
const getSenderInfo = React.useCallback((senderId: string): SenderInfo => {
if (senderId === currentUserId) {
@@ -153,7 +150,7 @@ const MessageBubbleInner: React.FC<MessageBubbleProps> = ({
}, [currentUserId, currentUser?.nickname, currentUser?.avatar, groupMembers]);
// 使用useMemo确保senderInfo在message.sender变化时重新计算
const senderInfo = React.useMemo((): SenderInfo | null => {
const senderInfo = useMemo((): SenderInfo | null => {
if (!isGroupChat) return null;
const senderId = message.sender_id;
@@ -204,6 +201,9 @@ const MessageBubbleInner: React.FC<MessageBubbleProps> = ({
return map;
}, [groupMembers]);
// FlashList 回收复用时重置内部状态
const messageKey = String(message.id);
// 记录按压位置
const handlePressIn = (event: GestureResponderEvent) => {
const { pageX, pageY } = event.nativeEvent;
@@ -464,13 +464,15 @@ const MessageBubbleInner: React.FC<MessageBubbleProps> = ({
// 使用 SwipeableMessageBubble 包裹消息内容
return (
<SwipeableMessageBubble
isMe={isMe}
onReply={handleSwipeReply}
enabled={!!onReply}
>
{messageContent}
</SwipeableMessageBubble>
<View style={{ width: '100%' }} key={messageKey}>
<SwipeableMessageBubble
isMe={isMe}
onReply={handleSwipeReply}
enabled={!!onReply}
>
{messageContent}
</SwipeableMessageBubble>
</View>
);
};
@@ -507,10 +509,6 @@ export const MessageBubble = React.memo(MessageBubbleInner, (prev, next) => {
if (prev.currentUser !== next.currentUser) return false;
if (prev.otherUser !== next.otherUser) return false;
if (prev.messageMap !== next.messageMap) return false;
if (prev.onLongPress !== next.onLongPress) return false;
if (prev.onImagePress !== next.onImagePress) return false;
if (prev.onReplyPress !== next.onReplyPress) return false;
if (prev.shouldShowTime !== next.shouldShowTime) return false;
return true;
});