I have list of comments. Every time user adds a new comment, I want that div and that div only to scroll to bottom. That div height is fixed and overflow is also set to scroll. I have found some answers to use dummy-div at the end of the comment list to scroll. I encountered 2 problems with that approach.
When used scrollIntoView to that div element, the entire body scrolls. Which is unwanted. I just want that div body to scroll to the last comment.
Say, I have a function, upon calling, scrolls to bottom.
handleScrollToBottom
. I called it right after the comment was added. But, it doesn't scroll to the bottom. Which makes sense. Because, if I am not wrong, updating the state doesn't update the state instantly. Let me demonstrate more with code
const Comment = () => {
const ref = useRef();
const handleScrollToBottom = () => {
//
ref.current.scrollIntoView();
};
const addComment = () => {
//
setAllComments((pre) => [...pre, { cmt: newCmt }]);
// Doesn't work here
handleScrollToBottom();
};
return (
<div>
{allComments.map((cmt) => (
<Comment cmt={cmt} />
))}
{/* Dummy Div to scroll to bottom */}
<div ref={ref}></div>
</div>
);
};
That was the second problem. So, I used useEffect
and put allComments.length
as a dependency.
useEffect(() => {
// Deleting a comment calls this function
handleScrollToBottom();
}, [allComments.length]);
That does work. But, the problem is, when a comment was deleted, it scrolls to bottom becasue the comments length changes which is not desired. Does anyone have any solution for my problem? I really appreciate it.
CodePudding user response:
If I understand the problem correctly you want the scrolling to happen only when a new comment is added.
So can you create a react state that keeps track of only the added comments, if that changes then scroll, this would ignore deletes.
const [commentAdded, setCommentAdded] = useState(0)
const addComment = () => {
setAllComments((pre) => [...pre, { cmt: newCmt }]);
setCommentAdded( commentAdded)
};
useEffect(() => {
handleScrollToBottom();
}, [commentAdded]);
CodePudding user response:
Instead of using state
to check if comments are added or removed, like @wpw has, you can add another ref
to keep track of whether comments were added or deleted. And only trigger scrollIntoView
when the ref
reflects comments are added:
const Comment = () => {
const ref = useRef();
const commentsAddedRef = useRef(false); // Checks if comments are added or removed
const handleScrollToBottom = () => {
//
ref.current.scrollIntoView();
};
const addComment = () => {
commentsAddedRef.current = true; // Set ref to true because comment is added
setAllComments((pre) => [...pre, { cmt: newCmt }]);
};
const removeComment = () => {
commentsAddedRef.current = false; // Set ref to false because comment is removed
...
}
useEffect(() => {
if(commentsAddedRef.current){ // Only triggers if comments are added
handleScrollToBottom();
}
}, [allComments.length]);
return (
<div>
{allComments.map((cmt) => (
<Comment cmt={cmt} />
))}
{/* Dummy Div to scroll to bottom */}
<div ref={ref}></div>
</div>
);
};