tencent cloud

即时通信 IM

MessageList State

Download
Focus Mode
Font Size
Last updated: 2025-07-22 16:21:48

MessageListState 概述

MessageListState 是一个与消息列表构建相关的状态管理中心,专门用于管理消息列表的状态和操作。它提供了消息列表的数据管理、分页加载、阅读回执设置、滚动控制等核心功能,是构建聊天界面的重要工具。
MessageListState 采用了响应式设计,能够自动监听底层数据变化并更新组件状态,同时提供了丰富的业务操作方法来满足不同的使用场景。

什么时候需要 MessageListState?

当目前的 MessageList 能力无法满足需求,或者希望借助底层数据重新开发 MessageList 时,可以使用 useMessageListState() 获取原始的数据源并进行重新开发。

属性列表

字段
类型
描述
messageList
readonly IMessageModel[] | undefined
消息列表数据
hasMoreOlderMessage
boolean | undefined
是否还有更多历史消息可加载
enableReadReceipt
boolean | undefined
是否启用阅读回执功能
isDisableScroll
boolean
是否禁用滚动
setIsDisableScroll
(isDisableScroll: boolean) => void
设置滚动状态的方法
loadMoreMessage
() => Promise<any>
加载更多消息的方法
setEnableReadReceipt
(enableReadReceipt: boolean | undefined) => void
设置阅读回执状态的方法

属性详细说明

messageList

类型: readonly IMessageModel[] | undefined
描述: 当前会话的消息列表数据。这是一个只读数组,包含了所有已加载的消息对象。每个消息对象包含消息内容、发送者信息、时间戳、状态等完整信息。当底层数据未加载完毕时,该值为 undefined

hasMoreOlderMessage

类型: boolean | undefined
描述: 标识是否还有更多的历史消息可以加载。当值为 true 时,表示还有更早的消息可以通过 loadMoreMessage 方法获取;当值为 false 时,表示已经加载了所有历史消息;当值为 undefined 时,表示加载状态未确定。

enableReadReceipt

类型: boolean | undefined
描述: 控制是否启用已读回执功能。当设置为 true 时,消息会显示已读状态;当设置为 false 时,不显示已读状态;当值为 undefined 时,表示用户未指定是否启用已读回执功能。

isDisableScroll

类型: boolean
描述: 控制消息列表的滚动行为。当设置为 true 时,禁用自动滚动功能;当设置为 false 时,允许正常滚动。通常在用户手动滚动查看历史消息时设置为 true,避免新消息到达时自动滚动影响用户体验。该字段的设置不会禁用页面的滚动,请在 dom 侧使用该字段控制。

setIsDisableScroll

类型: (isDisableScroll: boolean) => void
描述: 用于设置滚动状态的方法。接收一个布尔值参数来控制是否禁用滚动功能。

loadMoreMessage

类型: () => Promise<any>
描述: 异步加载更多历史消息的方法。调用该方法会向服务器请求更早的消息数据,并自动更新 messageListhasMoreOlderMessage 状态。

setEnableReadReceipt

类型: (enableReadReceipt: boolean | undefined) => void
描述: 用于设置阅读回执功能开关的方法。接收一个布尔值或 undefined 参数来控制是否启用阅读回执。

使用示例

以下是一个完整的 MessageList 组件示例,展示了如何使用 messageListhasMoreOlderMessageloadMoreMessage 来构建一个具有分页加载功能的消息列表:
import React, { useEffect, useRef, useState } from 'react';
import { useMessageListState } from '@tencentcloud/chat-uikit-react';
import type { MessageModel } from '@tencentcloud/chat-uikit-react';
import './MessageList.scss';

interface MessageListProps {
className?: string;
}

const MessageList: React.FC<MessageListProps> = ({ className }) => {
const {
messageList,
hasMoreOlderMessage,
loadMoreMessage,
isDisableScroll,
setIsDisableScroll,
} = useMessageListState();

const [isLoading, setIsLoading] = useState(false);
const messageListRef = useRef<HTMLDivElement>(null);
const prevScrollHeight = useRef<number>(0);

// 加载更多消息
const handleLoadMore = async () => {
if (isLoading || !hasMoreOlderMessage) return;

setIsLoading(true);
try {
// 记录当前滚动高度
if (messageListRef.current) {
prevScrollHeight.current = messageListRef.current.scrollHeight;
}

await loadMoreMessage();
} catch (error) {
console.error('加载更多消息失败:', error);
} finally {
setIsLoading(false);
}
};

// 处理滚动事件
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
const target = e.target as HTMLDivElement;
const { scrollTop, scrollHeight, clientHeight } = target;

// 检测是否滚动到顶部,触发加载更多
if (scrollTop === 0 && hasMoreOlderMessage && !isLoading) {
handleLoadMore();
}

// 检测用户是否在查看历史消息
const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
setIsDisableScroll(!isAtBottom);
};

// 保持滚动位置(加载更多消息后)
useEffect(() => {
if (messageListRef.current && prevScrollHeight.current > 0) {
const newScrollHeight = messageListRef.current.scrollHeight;
const scrollDiff = newScrollHeight - prevScrollHeight.current;
messageListRef.current.scrollTop = scrollDiff;
prevScrollHeight.current = 0;
}
}, [messageList]);

// 自动滚动到底部(新消息到达时)
useEffect(() => {
if (messageListRef.current && !isDisableScroll) {
messageListRef.current.scrollTop = messageListRef.current.scrollHeight;
}
}, [messageList, isDisableScroll]);

// 渲染单条消息
const renderMessage = (message: MessageModel) => (
<div key={message.ID} className="message-item">
<div className="message-sender">{message.nick || message.from}</div>
<div className="message-content">
{
(() => {
if (message.type === 'TIMTextElem') {
return <span className="text-message">{message.payload.text}</span>;
} else {
return <span>other message</span>;
}
})()
}
</div>
<div className="message-time">
{new Date(message.time * 1000).toLocaleTimeString()}
</div>
</div>
);

return (
<div className={`im-message-list-container ${className || ''}`}>
{/* 加载更多指示器 */}
{hasMoreOlderMessage && (
<div className="load-more-indicator">
{isLoading ? (
<div className="loading">加载中...</div>
) : (
<button onClick={handleLoadMore} className="load-more-btn">
加载更多消息
</button>
)}
</div>
)}

{/* 消息列表 */}
<div
ref={messageListRef}
className="message-list"
onScroll={handleScroll}
>
{messageList?.map(renderMessage)}
</div>

{/* 空状态 */}
{messageList?.length === 0 && (
<div className="empty-state">
暂无消息
</div>
)}
</div>
);
};

export default MessageList;

样式参考

.im-message-list-container {
display: flex;
flex-direction: column;
flex: 1 1 auto;
overflow: auto hidden;
.load-more-indicator {
padding: 10px;
text-align: center;
border-bottom: 1px solid #eee;
.loading {
color: #666;
font-size: 14px;
}
.load-more-btn {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #0056b3;
}
}
}
.message-list {
flex: 1;
overflow-y: auto;
min-height: 0;
padding: 10px;
.message-item {
margin-bottom: 15px;
padding: 10px;
background: #f5f5f5;
border-radius: 8px;
.message-sender {
font-weight: bold;
color: #333;
margin-bottom: 5px;
}
.message-content {
color: #666;
line-height: 1.5;
margin-bottom: 5px;
}
.message-time {
font-size: 12px;
color: #999;
text-align: right;
}
}
}
.empty-state {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: #999;
font-size: 14px;
}
}
这个示例展示了如何:
1. 使用 messageList 渲染消息列表。
2. 通过 hasMoreOlderMessage 判断是否显示加载更多按钮。
3. 调用 loadMoreMessage 实现分页加载。
4. 结合 isDisableScrollsetIsDisableScroll 优化滚动体验。
5. 处理加载状态和空状态的显示。

Help and Support

Was this page helpful?

Help us improve! Rate your documentation experience in 5 mins.

Feedback