refactor(ProcessPostUseCase, useCursorPagination, useDifferentialPosts): enhance post merging and loading states
- Introduced new methods for merging posts and comments efficiently, improving performance during data updates. - Updated loading state management in hooks to include initial loading and loading more states for better user feedback. - Refactored HomeScreen and PostDetailScreen to utilize the new loading states and merging logic, enhancing user experience during data fetching. - Improved pagination handling in useCursorPagination and useDifferentialPosts to ensure consistent data management across components.
This commit is contained in:
@@ -77,6 +77,7 @@ export const ChatScreen: React.FC = () => {
|
||||
|
||||
// 输入框区域高度(用于定位浮动 mention 面板)
|
||||
const [inputWrapperHeight, setInputWrapperHeight] = useState(60);
|
||||
const [showEdgeLoadingIndicator, setShowEdgeLoadingIndicator] = useState(false);
|
||||
const isPreloadingRef = useRef(false);
|
||||
const lastScrollYRef = useRef(0);
|
||||
const isUserDraggingRef = useRef(false);
|
||||
@@ -203,8 +204,15 @@ export const ChatScreen: React.FC = () => {
|
||||
loadMoreHistory,
|
||||
handleMessageListContentSizeChange,
|
||||
handleReachLatestEdge,
|
||||
setBrowsingHistory,
|
||||
} = useChatScreen();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingMore && showEdgeLoadingIndicator) {
|
||||
setShowEdgeLoadingIndicator(false);
|
||||
}
|
||||
}, [loadingMore, showEdgeLoadingIndicator]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (preloadCooldownTimerRef.current) {
|
||||
@@ -231,7 +239,7 @@ export const ChatScreen: React.FC = () => {
|
||||
return map;
|
||||
}, [messages]);
|
||||
|
||||
const renderMessage = ({ item, index }: { item: any; index: number }) => {
|
||||
const renderMessage = useCallback(({ item, index }: { item: any; index: number }) => {
|
||||
// inverted 下 renderItem 的 index 与时间顺序不一致,需回查原始序索引
|
||||
const logicalIndex = messageIndexMap.get(String(item.id)) ?? index;
|
||||
return (
|
||||
@@ -255,7 +263,26 @@ export const ChatScreen: React.FC = () => {
|
||||
onReply={handleReplyMessage}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}, [
|
||||
messageIndexMap,
|
||||
currentUserId,
|
||||
currentUser,
|
||||
otherUser,
|
||||
isGroupChat,
|
||||
groupMembers,
|
||||
otherUserLastReadSeq,
|
||||
selectedMessageId,
|
||||
messageMap,
|
||||
handleLongPressMessage,
|
||||
handleAvatarPress,
|
||||
handleAvatarLongPress,
|
||||
formatTime,
|
||||
shouldShowTime,
|
||||
handleImagePress,
|
||||
handleReplyMessage,
|
||||
]);
|
||||
|
||||
const keyExtractor = useCallback((item: any) => String(item.id), []);
|
||||
|
||||
// 获取正在输入提示
|
||||
const typingHint = getTypingHint();
|
||||
@@ -269,6 +296,11 @@ export const ChatScreen: React.FC = () => {
|
||||
viewportHeight: layoutMeasurement.height,
|
||||
};
|
||||
|
||||
// 离开最新消息端后进入“浏览历史”模式,屏蔽自动跟随到底
|
||||
if (contentOffset.y > 120) {
|
||||
setBrowsingHistory(true);
|
||||
}
|
||||
|
||||
// 仅用户手势主动回到底部时才解除历史阅读锁(避免加载阶段误解锁)
|
||||
const isScrollingTowardLatest = contentOffset.y < lastScrollYRef.current;
|
||||
if (
|
||||
@@ -282,13 +314,19 @@ export const ChatScreen: React.FC = () => {
|
||||
|
||||
// inverted 下历史端在“列表尾部”,对应 offset 增大且距离尾部变小
|
||||
const distanceToHistoryEdge = contentSize.height - (contentOffset.y + layoutMeasurement.height);
|
||||
const isScrollingTowardHistory = contentOffset.y > lastScrollYRef.current;
|
||||
lastScrollYRef.current = contentOffset.y;
|
||||
|
||||
const PRELOAD_HISTORY_THRESHOLD = 120;
|
||||
// 预加载阈值:按屏幕高度动态提前(至少 420),确保边界前开始加载
|
||||
const PRELOAD_HISTORY_THRESHOLD = Math.max(420, layoutMeasurement.height * 1.2);
|
||||
// 仅在真正接近边界时才显示旋转提示
|
||||
const EDGE_LOADING_INDICATOR_THRESHOLD = 60;
|
||||
const shouldShowEdgeIndicator = loadingMore && distanceToHistoryEdge <= EDGE_LOADING_INDICATOR_THRESHOLD;
|
||||
if (shouldShowEdgeIndicator !== showEdgeLoadingIndicator) {
|
||||
setShowEdgeLoadingIndicator(shouldShowEdgeIndicator);
|
||||
}
|
||||
|
||||
if (
|
||||
distanceToHistoryEdge <= PRELOAD_HISTORY_THRESHOLD &&
|
||||
isScrollingTowardHistory &&
|
||||
hasMoreHistory &&
|
||||
!loadingMore &&
|
||||
!loading &&
|
||||
@@ -304,7 +342,7 @@ export const ChatScreen: React.FC = () => {
|
||||
}, 350);
|
||||
});
|
||||
}
|
||||
}, [scrollPositionRef, hasMoreHistory, loadingMore, loading, loadMoreHistory, handleReachLatestEdge]);
|
||||
}, [scrollPositionRef, hasMoreHistory, loadingMore, loading, loadMoreHistory, handleReachLatestEdge, showEdgeLoadingIndicator, setBrowsingHistory]);
|
||||
|
||||
const handleContentSizeChange = useCallback((contentWidth: number, contentHeight: number) => {
|
||||
handleMessageListContentSizeChange(contentWidth, contentHeight);
|
||||
@@ -338,6 +376,7 @@ export const ChatScreen: React.FC = () => {
|
||||
onLayout={e => {
|
||||
scrollPositionRef.current.viewportHeight = e.nativeEvent.layout.height;
|
||||
}}
|
||||
onTouchEnd={handleDismiss}
|
||||
>
|
||||
{loading ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
@@ -349,10 +388,15 @@ export const ChatScreen: React.FC = () => {
|
||||
inverted
|
||||
data={displayMessages}
|
||||
renderItem={renderMessage}
|
||||
keyExtractor={(item: any) => String(item.id)}
|
||||
keyExtractor={keyExtractor}
|
||||
contentContainerStyle={listContentStyle as any}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
initialNumToRender={14}
|
||||
maxToRenderPerBatch={10}
|
||||
updateCellsBatchingPeriod={50}
|
||||
windowSize={9}
|
||||
removeClippedSubviews={Platform.OS !== 'web'}
|
||||
onScroll={handleMessageListScroll}
|
||||
onScrollBeginDrag={() => {
|
||||
isUserDraggingRef.current = true;
|
||||
@@ -368,7 +412,7 @@ export const ChatScreen: React.FC = () => {
|
||||
onContentSizeChange={handleContentSizeChange}
|
||||
/>
|
||||
)}
|
||||
{loadingMore && (
|
||||
{showEdgeLoadingIndicator && (
|
||||
<View
|
||||
pointerEvents="none"
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user