Virtuoso Message List Tutorial - Receive Messages
Part 5 - Receive Messages
Section titled “Part 5 - Receive Messages”In this part, we’re going to implement a simulation of receiving messages from the server. Since we have no actual backend, we’re going to use a button for that. Receiving messages has a specific scroll behavior; if the list is at the bottom, it should automatically scroll to the bottom. If the user has scrolled up to read previous messages, the list should remain at the same scroll position and display a notification that new messages are available. Let’s add a counter for the unread messages first:
const [unseenMessages, setUnseenMessages] = useState(0)Then, add the following button somewhere below the message list:
//...
<div style={{ display: 'flex', gap: '1rem', padding: '1rem' }}>
<button
onClick={() => {
const otherMessages = [createMessage(otherUser), createMessage(otherUser)]
setMessageListData((current) => {
return {
data: [...(current?.data ?? []), ...otherMessages],
scrollModifier: {
type: 'auto-scroll-to-bottom',
autoScroll: ({ atBottom, scrollInProgress }) => {
if (atBottom || scrollInProgress) {
return 'smooth'
}
setUnseenMessages((prev) => prev + otherMessages.length)
return false
},
},
}
})
}}
>
Receive 2 messages
</button>
</div>If everything works as expected, pressing the button will display a new message from another user with a smooth scroll animation.
Display the New Message Counter
Section titled “Display the New Message Counter”We will use the add the new message counter next to the scroll to bottom button, by passing the unseenMessages counter through the context prop. Let’s extend our context and pass the additional flag:
interface MessageListContext {
loadingNewer: boolean
loading: boolean
channel: ChatChannel
// highlight-next-line
unseenMessages: number
}
// ...
<VirtuosoMessageList<ChatMessage, MessageListContext>
key={channel.name}
// highlight-next-line
context={{ loading, loadingNewer, currentUser, unseenMessages }}Now, change the StickyFooter component to display the new message counter:
// highlight-next-line
const StickyFooter: MessageListProps['StickyFooter'] = ({ context: { unseenMessages } }) => {
const location = useVirtuosoLocation()
const virtuosoMethods = useVirtuosoMethods()
return (
<div style={{ position: 'relative' }}>
<div
style={{
position: 'absolute',
bottom: 10,
right: 50,
}}
>
{location.bottomOffset > 200 && (
<>
// highlight-next-line
{unseenMessages > 0 && <span>{unseenMessages} new messages</span>}
<button
style={{
backgroundColor: 'white',
border: '2px solid black',
borderRadius: '100%',
width: 30,
height: 30,
color: 'black',
}}
onClick={() => {
virtuosoMethods.scrollToItem({ index: 'LAST', align: 'end', behavior: 'auto' })
}}
>
▼
</button>
</>
)}
</div>
</div>
)
}Reset the New Message Counter
Section titled “Reset the New Message Counter”A more sophisticated logic can be implemented, but for now, we would like to reset the counter when the user scrolls to the bottom. Add the following code to the onScroll event handler:
const onScroll = React.useCallback(
(location: ListScrollLocation) => {
//highlight-start
if (location.bottomOffset < 100) {
setUnseenMessages(0)
}
//highlight-endScroll up the message list and press the button - the indicator of new messages should appear. Clicking the button will scroll to the bottom of the list and reset the indicator.