In React, how to divert the scrolling to another element?

Viewed 284

My APP has 3 divs: side, middle, and right.

The middle section will contain the content list of arbitrary number of items. It is set to the length of the vh. Thus, it will need to scroll when too many items are present.

The problem is when the user scroll over the side or right divs, nothing happens.

To solve, the problem, all scrolling should be diverted to the middle div, no matter where the pointer is hovering.

How can this be done in React?

2 Answers

Doing this in React is fairly straightforward. Here is a functional component I created that is working as desired:

import React from "react";
import { useEffect, useRef, useState } from "react";
import "./Content.css";

const Content = (props) => {
  
  const [contentHover, setContentHover] = useState(false);
  const contentRef = useRef(null);

  useEffect(() => {

    const handleScrolling = (event) => {
      if(contentRef !== null) {
        if(contentHover === false) {
          contentRef.current.scrollTop += event.deltaY;
        }
      }
    }

    window.addEventListener("wheel", handleScrolling);

    return () => {
      window.removeEventListener("wheel", handleScrolling);
    }
  })

  return (
    <div 
      className="content" 
      ref={contentRef}
      onMouseEnter={ () => { setContentHover(true) }}
      onMouseLeave={ () => { setContentHover(false) }}
    >
      {/* YOUR LIST OF CONTENT OR WHATEVER */}
    </div>
  )
}

export default Content; 

Explanation

There are three things that make this solution work.

First, I used useRef to get access to the element that I want to scroll. In my example, this is the div with the class content. In your case it will be your middle div. This is important because doing this gives access to the element's scrollTop property. Using scrollTop we can set the position of the element's scroll bar.

Second, I added state called contentHover using useState. I toggle its value between true and false using the onMouseEnter and onMouseLeve event handlers on div I want to scroll. When the mouse enters my div contentHover becomes true. When it leaves it becomes false. This is important because we don't want to double scroll the element i.e. make it scroll twice as fast. We will check if contentHover is false, meaning the mouse is not in the element we want to scroll, before applying our custom scroll function.

Finally, the useEffect hook. I added an event listener for the wheel event. When the wheel event is fired, the event object passed to the handleScrolling function contains a deltaY property. Inside handleScrolling I add deltaY to the ref element's scrollTop property to get a similar result as scrolling normally. Finally, I remove the event listener in useEffect's clean up function.

In summary, we aren't necessarily "diverting" scrolling to another element. Instead, we listen for the wheel event, keep a reference to the element we want to scroll, and then update that element's scrollTop whenever the event is fired.

Hope this helped you in some way!

Going by the first solution, I solved the smooth scroll problem by changing the code to this:

const handleScrolling = (event) => {
      if (contentRef !== null) {
        if (contentHover === false) {
          contentRef.current.scrollTo({
            top: contentRef.current.scrollTop + event.deltaY,
            behavior: "smooth",
          });
        }
      }
    };
Related