Home > Blockchain >  How to scroll to bottom in React
How to scroll to bottom in React

Time:08-30

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.

  1. 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.

  2. 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>
  );
};

  • Related