refactor: 优化聊天列表逻辑,当发送消息时滚动到底部

pull/13/head
moonrailgun 4 years ago
parent a82fa67243
commit a3b818d227

@ -1,4 +1,4 @@
import React from 'react'; import React, { useImperativeHandle, useRef } from 'react';
import { import {
ChatMessage, ChatMessage,
getMessageTimeDiff, getMessageTimeDiff,
@ -10,49 +10,73 @@ import { Divider } from 'antd';
interface ChatMessageListProps { interface ChatMessageListProps {
messages: ChatMessage[]; messages: ChatMessage[];
} }
export const ChatMessageList: React.FC<ChatMessageListProps> = React.memo( export interface ChatMessageListRef {
(props) => { scrollToBottom: () => void;
return ( }
<div className="flex-1 overflow-y-scroll flex flex-col-reverse"> export const ChatMessageList = React.forwardRef<
<div> ChatMessageListRef,
{props.messages.map((message, index, arr) => { ChatMessageListProps
let showDate = true; >((props, ref) => {
let showAvatar = true; const containerRef = useRef<HTMLDivElement>(null);
const messageCreatedAt = new Date(message.createdAt ?? '');
if (index > 0) { useImperativeHandle(ref, () => ({
// 当不是第一条数据时 scrollToBottom() {
requestAnimationFrame(() => {
if (!containerRef.current) {
return;
}
containerRef.current.scrollTo({
top: containerRef.current.scrollHeight,
behavior: 'smooth',
});
});
},
}));
// 进行时间合并 return (
const prevMessage = arr[index - 1]; <div
if ( className="flex-1 overflow-y-scroll flex flex-col-reverse"
!shouldShowMessageTime( ref={containerRef}
new Date(prevMessage.createdAt ?? ''), >
messageCreatedAt <div>
) {props.messages.map((message, index, arr) => {
) { let showDate = true;
showDate = false; 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) { if (showDate === false) {
showAvatar = prevMessage.author !== message.author; showAvatar = prevMessage.author !== message.author;
}
} }
}
return ( return (
<div key={message._id}> <div key={message._id}>
{showDate && ( {showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-none"> <Divider className="text-sm opacity-40 px-6 font-normal select-none">
{getMessageTimeDiff(messageCreatedAt)} {getMessageTimeDiff(messageCreatedAt)}
</Divider> </Divider>
)} )}
<ChatMessageItem showAvatar={showAvatar} payload={message} /> <ChatMessageItem showAvatar={showAvatar} payload={message} />
</div> </div>
); );
})} })}
</div>
</div> </div>
); </div>
} );
); });
ChatMessageList.displayName = 'ChatMessageList'; ChatMessageList.displayName = 'ChatMessageList';

@ -1,9 +1,9 @@
import { Skeleton } from 'antd'; import { Skeleton } from 'antd';
import React from 'react'; import React, { useRef } from 'react';
import { useConverseMessage } from 'tailchat-shared'; import { useConverseMessage } from 'tailchat-shared';
import { AlertErrorView } from '../AlertErrorView'; import { AlertErrorView } from '../AlertErrorView';
import { ChatInputBox } from './ChatInputBox'; import { ChatInputBox } from './ChatInputBox';
import { ChatMessageList } from './ChatMessageList'; import { ChatMessageList, ChatMessageListRef } from './ChatMessageList';
const ChatBoxPlaceholder: React.FC = React.memo(() => { const ChatBoxPlaceholder: React.FC = React.memo(() => {
return ( return (
@ -40,6 +40,7 @@ export const ChatBox: React.FC<ChatBoxProps> = React.memo((props) => {
converseId, converseId,
isGroup, isGroup,
}); });
const chatMessageListRef = useRef<ChatMessageListRef>(null);
if (loading) { if (loading) {
return <ChatBoxPlaceholder />; return <ChatBoxPlaceholder />;
@ -51,16 +52,18 @@ export const ChatBox: React.FC<ChatBoxProps> = React.memo((props) => {
return ( return (
<div className="w-full h-full flex flex-col select-text"> <div className="w-full h-full flex flex-col select-text">
<ChatMessageList messages={messages} /> <ChatMessageList ref={chatMessageListRef} messages={messages} />
<ChatInputBox <ChatInputBox
onSendMsg={(msg) => onSendMsg={(msg) => {
handleSendMessage({ handleSendMessage({
converseId: props.converseId, converseId: props.converseId,
groupId: props.groupId, groupId: props.groupId,
content: msg, content: msg,
}) }).then(() => {
} chatMessageListRef.current?.scrollToBottom();
});
}}
/> />
</div> </div>
); );

Loading…
Cancel
Save