我正在 React(准确地说是 Nextjs)中制作一个聊天应用程序,到目前为止我已经完成了所有组件:聊天容器,有一个标题、一个消息列表和一个输入。该代码正在侦听新消息,每条新消息都会在消息列表组件中添加一个新消息子组件。
这是我想要实现的聊天的示意图版本。每条消息都包含文本本身和人物的头像。消息数据还包含作者,因此使用弹性显示,它将消息放置在消息列表的一侧或另一侧。我希望头像仅出现在每一侧的最后一组消息上。
我认为应该由
MessageList
组件负责每次都知道哪条消息是每一方的最后一条消息,但我不确定如何实现它。首先我尝试使用CSS,但我只能显示在每侧的最后一条消息中(:last-child
),而不能显示在每组每侧的最后一条消息中。其次,有一个数组标记每条最后一条消息,但随后我必须重新排序并搜索前一条消息,这导致头像出现在错误的消息中。此外,为每条消息设置一个状态似乎并不是最佳和高效的。
<ChatContainer>
<Header />
<MessagesList >
<Message author='me' />
<Message author='me' /> // <- avatar here
<Message author='them' />
<Message author='them' /> // <- avatar here
<Message author='me' />
<Message author='me' />
<Message author='me' /> // <- avatar here
<MessageList />
<Input />
<ChatContainer />
我的问题是,如何高效地以“reactjs 方式”跟踪每一侧每组消息的最后一条消息?
要在每个组中显示头像,只需检查所有消息,如果当前消息作者!==下一条消息作者,则将头像道具添加到当前
此外,为每条消息设置一个状态似乎并不是最佳选择, 高效。
为此,我需要查看您的代码,您可以创建不同的问题(对于其他人,当他们会像这样搜索时)并在此处粘贴链接
这是一个值得尝试的解决方案:
设置聊天消息类型如下:
type ChatMessage = {
message: string,
author: string,
isLastOne: boolean // avatar only appears when this is true
}
const [messagesArr, setMessagesArr] = useState<ChatMessage[]>([]);
假设,
me
和them
消息存储在这个单一的messagesArr
状态中。
me
发送一条消息附加到我自己的消息中,将头像推送到更新后的 <Message author='me' />
(反之亦然);
在
me
发消息到我的消息列表之前,them
先发消息,打断了我自己的消息。
const initialData = [{message: "1", author: "me", isLastOne: true}]
const [messagesArr, setMessagesArr] = useState(initialData);
const newMessage = {message: "2", author: "me", isLastOne: true}; // newMessage.isLastOne always set to true
function pushNewMessage(messagesArr, newMessage) {
newState = [...messagesArr]; // make a copy
// Only when user is appending it's own message should we update the previous last element
const isUpdateOwnMessage = newState[newState.length - 1].author === newMessage.author;
if(isUpdateOwnMessage) {
newState[newState.length - 1].isLastOne = false; // update previous last element's isLastOne value
}
newState.push(newMessage);
return newState;
}
setMessagesArr(pushNewMessage(messagesArr, newMessageFromMe))
第一种情况:当附加到我们自己的消息时,在此之前,我们将
previous last
元素的 isLastOne
更改为 false,并且由于新消息始终将 isLastOne
值设置为 true,这应该正确渲染头像;
第二种情况:消息被
them
打断,我们可以直接推送到列表。
由于头像的出现是由
isLastOne
和 author
值决定的,那么,我们可以安全地将其显示在作者消息列表的末尾,并且通过在推送之前检查最后一个元素的所有者,我们可以正确更新状态。不确定这是否有意义。
我找到了解决问题的方法。这就能完成工作。
{conversation.map((message, index) => {
const showAvatar = index === conversation.length - 1 || message.sender.userId !== conversation[index + 1].sender.userId;
return (
<div key={index}>
{showAvatar && <div className='avatar'></div> }
<div>
{message.text}
</div>
</div>
)
})}