feat: 使用虚拟列表替换渲染的普通聊天列表

pull/13/head
moonrailgun 3 years ago
parent bff5caaa54
commit 80bd0b608d

@ -36,7 +36,7 @@ function findMessageIndexWithId(
return messages.findIndex((m) => m._id === messageId);
}
interface VirtualizedMessageListProps {
export interface VirtualizedMessageListProps {
messages: ChatMessage[];
onUpdateReadedMessage: (lastMessageId: string) => void;
}

@ -1,116 +1,18 @@
import React, {
useCallback,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import React from 'react';
import {
ChatMessage,
getMessageTimeDiff,
shouldShowMessageTime,
useUpdateRef,
} from 'tailchat-shared';
import { ChatMessageItem } from './Item';
import { Divider } from 'antd';
interface ChatMessageListProps {
messages: ChatMessage[];
onUpdateReadedMessage: (lastMessageId: string) => void;
}
export interface ChatMessageListRef {
scrollToBottom: () => void;
}
export const ChatMessageList = React.forwardRef<
ChatMessageListRef,
ChatMessageListProps
>((props, ref) => {
const containerRef = useRef<HTMLDivElement>(null);
useImperativeHandle(ref, () => ({
scrollToBottom() {
requestAnimationFrame(() => {
if (!containerRef.current) {
return;
}
containerRef.current.scrollTo({
top: containerRef.current.scrollHeight,
behavior: 'smooth',
});
});
},
}));
const onUpdateReadedMessageRef = useUpdateRef(props.onUpdateReadedMessage);
useEffect(() => {
if (props.messages.length === 0) {
return;
}
if (containerRef.current?.scrollTop === 0) {
// 当前列表在最低
onUpdateReadedMessageRef.current(
props.messages[props.messages.length - 1]._id
);
}
}, [props.messages.length]);
const handleScroll = useCallback(() => {
if (props.messages.length === 0) {
return;
}
if (containerRef.current?.scrollTop === 0) {
onUpdateReadedMessageRef.current(
props.messages[props.messages.length - 1]._id
);
}
}, [props.messages]);
return (
<div
className="flex-1 overflow-y-scroll flex flex-col-reverse"
ref={containerRef}
onScroll={handleScroll}
>
<div>
{props.messages.map((message, index, arr) => {
let showDate = true;
let showAvatar = true;
const messageCreatedAt = new Date(message.createdAt ?? '');
if (index > 0) {
// 当不是第一条数据时
// 进行时间合并
const prevMessage = arr[index - 1];
if (
!shouldShowMessageTime(
new Date(prevMessage.createdAt ?? ''),
messageCreatedAt
)
) {
showDate = false;
}
// 进行头像合并(在同一时间块下 且发送者为同一人)
if (showDate === false) {
showAvatar = prevMessage.author !== message.author;
}
}
return (
<div key={message._id}>
{showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-none">
{getMessageTimeDiff(messageCreatedAt)}
</Divider>
)}
<ChatMessageItem showAvatar={showAvatar} payload={message} />
</div>
);
})}
VirtualizedMessageList,
VirtualizedMessageListProps,
} from './VirtualizedList';
export const ChatMessageList: React.FC<VirtualizedMessageListProps> =
React.memo((props) => {
return (
<div className="flex-1">
<VirtualizedMessageList
messages={props.messages}
onUpdateReadedMessage={props.onUpdateReadedMessage}
/>
</div>
</div>
);
});
);
});
ChatMessageList.displayName = 'ChatMessageList';

@ -3,7 +3,7 @@ import { ChatBoxContextProvider, useConverseMessage } from 'tailchat-shared';
import { AlertErrorView } from '../AlertErrorView';
import { ChatBoxPlaceholder } from './ChatBoxPlaceholder';
import { ChatInputBox } from './ChatInputBox';
import { ChatMessageList, ChatMessageListRef } from './ChatMessageList';
import { ChatMessageList } from './ChatMessageList';
import { ChatReply } from './ChatReply';
import { useMessageAck } from './useMessageAck';
@ -24,7 +24,6 @@ const ChatBoxInner: React.FC<ChatBoxProps> = React.memo((props) => {
converseId,
isGroup,
});
const chatMessageListRef = useRef<ChatMessageListRef>(null);
const { updateConverseAck } = useMessageAck(converseId, messages);
if (loading) {
@ -38,7 +37,6 @@ const ChatBoxInner: React.FC<ChatBoxProps> = React.memo((props) => {
return (
<div className="w-full h-full flex flex-col select-text">
<ChatMessageList
ref={chatMessageListRef}
messages={messages}
onUpdateReadedMessage={updateConverseAck}
/>
@ -51,9 +49,6 @@ const ChatBoxInner: React.FC<ChatBoxProps> = React.memo((props) => {
converseId: props.converseId,
groupId: props.groupId,
content: msg,
}).then(() => {
// 发送消息后滚动到底部
chatMessageListRef.current?.scrollToBottom();
});
}}
/>

Loading…
Cancel
Save