mirror of https://github.com/msgbyte/tailchat
feat: 使用虚拟列表替换渲染的普通聊天列表
parent
bff5caaa54
commit
80bd0b608d
@ -1,116 +1,18 @@
|
|||||||
import React, {
|
import React from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useRef,
|
|
||||||
} from 'react';
|
|
||||||
import {
|
import {
|
||||||
ChatMessage,
|
VirtualizedMessageList,
|
||||||
getMessageTimeDiff,
|
VirtualizedMessageListProps,
|
||||||
shouldShowMessageTime,
|
} from './VirtualizedList';
|
||||||
useUpdateRef,
|
|
||||||
} from 'tailchat-shared';
|
export const ChatMessageList: React.FC<VirtualizedMessageListProps> =
|
||||||
import { ChatMessageItem } from './Item';
|
React.memo((props) => {
|
||||||
import { Divider } from 'antd';
|
return (
|
||||||
|
<div className="flex-1">
|
||||||
interface ChatMessageListProps {
|
<VirtualizedMessageList
|
||||||
messages: ChatMessage[];
|
messages={props.messages}
|
||||||
onUpdateReadedMessage: (lastMessageId: string) => void;
|
onUpdateReadedMessage={props.onUpdateReadedMessage}
|
||||||
}
|
/>
|
||||||
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>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
});
|
||||||
});
|
|
||||||
ChatMessageList.displayName = 'ChatMessageList';
|
ChatMessageList.displayName = 'ChatMessageList';
|
||||||
|
|||||||
Loading…
Reference in New Issue