MessageList State
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>描述: 异步加载更多历史消息的方法。调用该方法会向服务器请求更早的消息数据,并自动更新
messageList 和 hasMoreOlderMessage 状态。setEnableReadReceipt
类型:
(enableReadReceipt: boolean | undefined) => void描述: 用于设置阅读回执功能开关的方法。接收一个布尔值或
undefined 参数来控制是否启用阅读回执。使用示例
以下是一个完整的 MessageList 组件示例,展示了如何使用
messageList、hasMoreOlderMessage 和 loadMoreMessage 来构建一个具有分页加载功能的消息列表: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>)}{/* 消息列表 */}<divref={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. 结合
isDisableScroll 和 setIsDisableScroll 优化滚动体验。5. 处理加载状态和空状态的显示。