DEV Community

Cover image for Real Scroll for a Chat Application
Martinez
Martinez

Posted on • Updated on

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.

Twitch chat

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>
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 = () => {}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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])
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)