Real Scroll for a Chat Application
One of the challenges when creating a chat application is efficient scroll control, especially as new messages continue to arrive and older messages can get lost in the message container.
In the chat app world, scroll is a critical feature that affects the user experience.
In this post, we will learn how to create an efficient scroll in a chat application using Next.js / React
. The logic can also be applied to Vanilla JavaScript
.
Just Show Me the Code
Without further ado, here’s a scroll setup that handles both new and old messages:
import { useState, useEffect, useRef } from 'react'
function Chat() {
const [messages, setMessages] = useState<string[]>([])
const container = useRef<HTMLDivElement>(null)
const Scroll = () => {
const { offsetHeight, scrollHeight, scrollTop } = container.current as HTMLDivElement
if (scrollHeight <= scrollTop + offsetHeight + 100) {
container.current?.scrollTo(0, scrollHeight)
}
}
useEffect(() => {
Scroll()
}, [messages])
return <div ref={container}>{messages}</div>
}
Feel free to copy paste it in your project.
If you don’t care how this works, you can stop here! The rest of this post is for those who want to understand the logic behind the code.
Code Extraction
Here I show you how to efficiently control the scroll in just 3 simple steps. It's actually quite simple.
1. Identify the message container.
This component is simple and only has the function of displaying messages. However, In complex apps, more styling is needed to make messages visually appealing.
<div>{messages}</div>
2. Get a reference to this element.
These properties must be mutable and must “persist” in new renderings, so it can't be a regular variable. We want something more like an instance field.
useRef()
gives us exactly that:
const container = useRef()
Hooks use a similar concept to store any value that can change. A reference is like a container where you can store anything.
useRef()
is a hook in React that allows you to access and manipulate a value that persists across multiple renders. It is ideal for storing properties, precisely what we need.
const container = useRef<HTMLDivElement>(null)
<div ref={container}>{messages}</div>
3. Access the relevant properties to control the scroll.
Before going deeper into the implementation, let's briefly describe the use of each property we are going to use:
-
The height of the element scrollHeight.
-
The number of pixels that the content of the element has been vertically displaced scrollTop.
-
The height of the element, including vertical padding and borders offsetHeight.
-
Moves the viewer to a specific set of coordinates on the element scrollTo.
Let's start by creating a function, which will be responsible for handling the scrolling logic in our chat application.
const Scroll = () => {}
The Scroll()
function checks the current scroll position of the element referenced by the container
variable.
In the following, we will use destructuring to access three of its important properties: offsetHeight
, scrollHeight
y scrollTop
.
const { offsetHeight, scrollHeight, scrollTop } = container.current as HTMLDivElement
Next, we do a comparison to determine if the user has reached the end of the content with a margin of 100 pixels
. If this condition is met, we use the scrollTo
method to automatically scroll to the end of the content and view the last messages.
if (scrollHeight <= scrollTop + offsetHeight + 100) {
container.current?.scrollTo(0, scrollHeight)
}
But when is it necessary to activate the function? 🤔
To do this, we use the useEffect
hook of React, which allows us to execute a function at a specific time in the lifecycle of our application. In this case, we are saying that the Scroll()
function should be executed every time the status of the messages
in our chat application changes.
useEffect(() => {
Scroll()
}, [messages])
Thanks to [messages]
, our effect is re-executed each time we receive a new message. In this way, we ensure that the Scroll function is executed each time a new message is added to the conversation.
Closing Thoughts
After adding the Scroll()
feature to your chat application, it is important to remember that this is only a basic example. In more complex applications, more formatting and styling will probably be needed to make messages appealing to users, and additional features such as scroll pause or message search can also be added. Overall, scrolling logic is only one part of building a complete chat application and there is much more to do before it is ready for use.