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 (shouldGroupByUser) and the typing indicator, which renders only with aTypingIndicatoroverride. - Pass
react-virtuosooptions throughadditionalVirtuosoProps, rather than the deprecateddefaultItemHeight,overscanandscrollSeekPlaceHolderprops. - 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. Its components are merged with the list's, and its scrollerRef and totalListHeightChanged are called after the list's own handlers. |
|
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. |
|
defaultItemHeight |
number |
Deprecated: use additionalVirtuosoProps.defaultItemHeight. The height the list estimates with before it measures the items. |
|
groupStyles |
(message, previousMessage, nextMessage, noGroupByUser, maxTimeBetweenGroupedMessages?) => GroupStyle |
getGroupStyles |
Decides each message's group style. The list passes noGroupByUser as the opposite of shouldGroupByUser. |
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. |
overscan |
number |
0 |
Deprecated: use additionalVirtuosoProps.overscan. Extra content to render beyond the visible area. |
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. |
|
scrollSeekPlaceHolder |
ScrollSeekConfiguration & { placeholder: ComponentType<ScrollSeekPlaceholderProps> } |
Deprecated: use additionalVirtuosoProps.scrollSeekConfiguration and additionalVirtuosoProps.components.ScrollSeekPlaceholder. Renders placeholders while the user scrolls fast. |
|
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. |
shouldGroupByUser |
boolean |
false |
Groups consecutive messages from the same sender. |
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 passes these props to every Message it renders: additionalMessageComposerProps, formatDate, reactionDetailsSort, renderText and sortReactions. They are documented on Message.
The list also passes showAvatar to each Message, but Message doesn't hand it to the message UI, so it has no effect.
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 |