VirtualizedMessageList
VirtualizedMessageList renders the messages of the channel or the thread it sits in, like MessageList, but keeps only the messages near the visible area in the DOM, with react-virtuoso. Message list UI compares the two lists.
Best practices
- Use it for very long histories, or channels with a lot of traffic such as livestreams. Otherwise
MessageListis simpler. - Remember what is off by default here and on in
MessageList: date separators (withDateSeparator), grouping by sender (groupByUser) and the typing indicator, which renders only with aTypingIndicatoroverride. - Pass
react-virtuosooptions throughadditionalVirtuosoProps. - Keep message UIs light. The list mounts and unmounts them as the user scrolls, and measures each one.
- Don't rely on a message's DOM node: it exists only while the message is near the visible area.
Basic usage
import {
Channel,
ChannelHeader,
MessageComposer,
VirtualizedMessageList,
} from "stream-chat-react";
export const LivestreamPanel = () => (
<Channel channel={channel}>
<ChannelHeader />
<VirtualizedMessageList
additionalVirtuosoProps={{ defaultItemHeight: 60 }}
stickToBottomScrollBehavior="auto"
withDateSeparator
/>
<MessageComposer />
</Channel>
);defaultItemHeight gives the list a height to estimate with before it measures the messages. stickToBottomScrollBehavior="auto" follows new messages without a smooth scroll, which keeps up with a fast channel.
Scroll behavior
- Opening. The list opens at the latest message, with its end in view. After a jump, it opens with the target message in the middle.
- Following new messages. While the user is at the bottom, the list follows new messages with
stickToBottomScrollBehavior. When the user sends a message, the list scrolls to it even if they were scrolled up. It doesn't follow while it shows an older window, or withsuppressAutoscroll. - Loading pages. Reaching the top loads older messages. Reaching the bottom of an older interval loads newer ones.
- Coming back. With
scrollToLatestMessageOnFocus, the list scrolls to the latest message when the window regains focus after messages arrived in the background.
How the paginator holds intervals of messages is on Message paginators.
Notifications and unread UI
Like MessageList, the list renders the unread separator, UnreadMessagesNotification in a channel, NewMessageNotification, the scroll-to-latest button, and a NotificationList for its panel. Two parts differ:
- The typing indicator renders below the messages only when you register a
TypingIndicatoroverride. - A Giphy preview renders with
GiphyPreviewMessagebelow the messages whenseparateGiphyPreviewis on.
Jumps on screen explains when the floating elements show.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
additionalVirtuosoProps |
VirtuosoProps from react-virtuoso |
Props for the underlying Virtuoso, applied over the list's own. react-virtuoso options such as defaultItemHeight, overscan and scrollSeekConfiguration go here. Its components are merged with the list's, and its scrollerRef and totalListHeightChanged are called after the list's own handlers. With useWindowScroll, the floating date separator takes its date from the first rendered message, so it can lag behind the messages on screen. |
|
closeReactionSelectorOnClick |
boolean |
Closes the reaction selector once a reaction is picked. | |
customMessageRenderer |
(messageList: RenderedMessage[], index: number) => ReactElement |
Renders each item in place of the list's own renderer, which renders date separators, system messages, the unread separator and Message. It receives the processed list and the item's index. The list passes none of the props it drills to messages to the items your renderer draws; pass them to the Message you render. |
|
getGroupStyles |
(params: GetGroupStylesParams) => GroupStyle |
getGroupStyles |
Decides each message's group style. It receives the list's groupByUser in its argument. |
groupByUser |
boolean |
false |
Groups consecutive messages from the same sender. |
hideDeletedMessages |
boolean |
false |
Leaves deleted messages out of the list. |
hideNewMessageSeparator |
boolean |
false |
Turns off the date separator added before the first message that arrived since the user last read the channel. |
maxTimeBetweenGroupedMessages |
number |
no limit | The longest gap, in milliseconds, between two messages of one group. |
returnAllReadData |
boolean |
false |
Gives every own message its read and delivery data. By default only the last own message gets it. |
reviewProcessedMessage |
ProcessMessagesParams["reviewProcessedMessage"] |
Called for each message as the list processes it. It returns the items to render in place of changes, the message with any separator added before it. |
|
scrollToLatestMessageOnFocus |
boolean |
false |
Scrolls to the latest message when the window regains focus, if messages arrived while it was in the background. |
separateGiphyPreview |
boolean |
false |
Renders a Giphy preview with GiphyPreviewMessage below the messages, instead of in the list. |
showUnreadNotificationAlways |
boolean |
false |
Also shows the unread notification while the unread separator is below the visible area. |
stickToBottomScrollBehavior |
"smooth" | "auto" |
"smooth" |
How the list follows new messages while at the bottom. "auto" jumps without animation, for channels with a lot of traffic. |
suppressAutoscroll |
boolean |
false |
Stops the list from following new messages. |
withDateSeparator |
boolean |
false |
Adds date separators between days, and the floating date at the top while scrolling. |
The list also takes these props and passes them to every <Message/> it renders: closeReactionSelectorOnClick, formatDate, onMentionsClick, onMentionsHover, onUserClick, onUserHover, reactionDetailsSort, renderText, showAvatar, sortReactions and unsafeHTML. They are documented on Message. unsafeHTML also reaches the MessageSystem override, by default <EventComponent/>. With it set, <EventComponent/> renders a system message's html when it has one, and its text otherwise.
These props also reach:
- The parent message above the replies, in a thread.
- The Giphy preview that
separateGiphyPreviewrenders below the messages.GiphyPreviewMessageis typed withMessagePropsand passes its props toMessage.
To the parent message and the Giphy preview, the list passes only the props you set. A ThreadHead or GiphyPreviewMessage override that sets a prop and then spreads its props, such as <Message showAvatar {...props} />, keeps its own value.
With customMessageRenderer, the parent message and the Giphy preview still get these props.
The list renders each message with the VirtualMessage override if one is set, and otherwise with MessageUI. See ComponentContext.
Related hooks
| Hook | Returns |
|---|---|
useVirtualizedMessageListContext() |
scrollToBottom, inside VirtualizedMessageList only. See VirtualizedMessageListContext |
useMessagePaginator() |
the paginator the list renders: thread.messagePaginator inside a Thread, otherwise channel.messagePaginator |
useChannel(), useThreadContext() |
the channel and the thread whose paginator the list renders |
useStateStore(store, selector) |
a selection of the paginator's state |
useMessageContext() |
the message and its handlers, inside each message the list renders |