'Scroll to the last item of a mapped array

I have a Message component that displays all the messages(incoming and outgoing) in one thread.

I would like the last message/a newly typed message/incoming message to always appear at the bottom of the conversation. Kind of like what all chats/messaging apps do.

Here is my code:

import React, { useRef } from "react";

const dummy = useRef();

...

dummy?.current?.scrollIntoView(true, {
    behaviour: "auto",
});

... 

<div className="">
  <Paper
    elevation={0}
    sx={{
      backgroundColor: "#fafafa",
      maxHeight: 200,
      overflow: "auto",
    }}
  >
    {messages.map((message, idx) => (
      <div key={idx} ref={dummy}>
        <Message message={message} name={name} />
      </div>
    ))}
    {/* I tried this also
    <div ref={dummy}></div> */}
  </Paper>
</div>

I want all the messages that can fit in the parent div with maxHeight: 200 to be displayed with the last message just at the bottom when I click on the conversation/thread. Currently, the WHOLE page scrolls to bottom instead of just the messages in the thread. The page should remain stationary.

How do I do this?



Solution 1:[1]

The problem is you are passing the ref to the div element in which the Message component is rendered. I would suggest you use a dummy div at the end of your chat and then scroll to that whenever your component is updated.

return (
    <div
      className="messagesWrapper"
      style={{ background: "white", border: "2px red solid" }}
    >
      {messages.map((message) => (
        <span key={message}>{message}</span>
      ))}
      <div ref={dummy} />
    </div>
  );

The ref element is updated in useEffect.

const dummy = useRef(null);
useEffect(() => {
  dummy.current.scrollIntoView({ behavior: "smooth" });
}, [messages]);

Attaching a sandbox for reference.

Solution 2:[2]

I think this will work:

React.useEffect(() => {
    dummy.current.scrollTop = dummy.current.scrollHeight
})

Solution 3:[3]

So what you can do is create a useRef and then initiate it as null

Then when you .map over your array to render the objects, run a function to check if it's the last item in the array

If it is the last object in the array, attach the ref to it

Then have a useEffect with the ref in the dependency array

If the useRef get's set with a new value, from the .map,in your useEffect, have a scrollTo behavior, smooth, function that scrolls to it

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mchowdam
Solution 2 Habibullah Rezaie
Solution 3 E_net4 - Krabbe mit Hüten