'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 |