0

I need to execute a function only when the user is horizontally scrolling. And I need it onScroll event. How to do this in React?

<div style={{position: "absolute", width: "50%", height: "50%", overflow: "scroll"}}>
  <table onScroll={...here I need to execute function only on right scroll}>
      ...
  </table>
</div>

EDIT: Solution

const tableRef = useRef(null);

const onScroll = () => { 
  console.log(tableRef.current?.scrollLeft)
 }

<div style={{position: "absolute", width: "50%", height: "50%", overflow: "scroll"}}>
  <table ref={tableRef} onScroll={onScroll}>
      ...
  </table>
</div>
  • Does this answer your question? [Is there a way to detect horizontal scroll only without triggering a browser reflow](https://stackoverflow.com/questions/42112158/is-there-a-way-to-detect-horizontal-scroll-only-without-triggering-a-browser-ref) – David Yappeter Mar 10 '22 at 14:55
  • dont forget to wrap it around `useEffect()` onmount, and onunmount (if you are using hooks) – David Yappeter Mar 10 '22 at 14:55
  • I usually read and test all possible solutions from Stackoverflow before asking questions. The answers are not working, and are a bit outdated, so that is why I want to check if there has been some improvement on this. @DavidYappeter – Amel Amcë Muminovic Mar 10 '22 at 15:19
  • Okay, gimme some minutes to make it in react – David Yappeter Mar 10 '22 at 15:20
  • What if i tell you that ref can be used. Is it absolutely necessary for you to use onScroll event? – Harry Mar 10 '22 at 15:49
  • What if I tell you that worked @Harry – Amel Amcë Muminovic Mar 10 '22 at 16:12
  • Well i never use ref to take a scroll value before, but what variable did you take out from `ref.current.[variable?]`, I only know that there is `offset` value from `ref`, but never heard of scroll value. @Harry – David Yappeter Mar 10 '22 at 16:15
  • @DavidYappeter We can access anything related to scroll from ref. Properties like ```offsetTop```, ```offsetLeft```, ```scrollLeft```, ```scrollTop```, ```scrollHeight```, ```scrollWidth```, ```clientHeight```, ```clientWidth```. The signature is the same for all like: ```ref.current.scrollTop```. Recently I developed auto-scroll feature with speed parameter for multiple tables in one page using single ref. Worked like a charm. – Harry Mar 10 '22 at 16:24
  • Ahh okay, that give me an idea – David Yappeter Mar 10 '22 at 16:39
  • Wait, so how you listen to the scroll change? I try something like this `useEffect(() => {}, [refer.current.scrollLeft])`, but that is not possible because `current` is null before it is attached to the component. @Harry – David Yappeter Mar 10 '22 at 17:04
  • I have updated my question with working solution – Amel Amcë Muminovic Mar 10 '22 at 17:32
  • @DavidYappeter Basically I used ```refer.current.scrollBy({top: 0, left: 100px})``` and run it with setInterval inside useEffect in all the directions one by one by checking if it reached vertical end or horizontal end and then recursively call the function again. I further optimised it with scroll speed which ```scrollBy``` doesn't provide. It was a complex requirement and i did with ref easily. I'd be happy to help elsewhere since I can't explain much in comments here. – Harry Mar 10 '22 at 18:01
  • @DavidYappeter Basically I used ```refer.current.scrollBy({top: 0, left: 100px})``` and run it with setInterval inside useEffect in all the directions one by one by checking if it reached vertical end or horizontal end and then recursively call the function again. I further optimised it with scroll speed which ```scrollBy``` doesn't provide. It was a complex requirement and i did with ref easily. I'd be happy to help elsewhere since I can't explain much in comments here. – Harry Mar 10 '22 at 18:02
  • Okay, I understand the setInterval one. – David Yappeter Mar 11 '22 at 01:37

1 Answers1

0

How about this ?

codesandbox: https://codesandbox.io/s/withered-sound-rkokr9

You can check the console, it only printout value on horizontal scroll.

import { useEffect } from "react";
import "./styles.css";

export default function App() {
  useEffect(() => {
    var ticking = false;
    var lastScrollLeft = 0;

    const onScroll = () => {
      if (!ticking) {
        window.requestAnimationFrame(function () {
          var documentScrollLeft = window.scrollX;
          if (lastScrollLeft != documentScrollLeft) {
            console.log(
              "only scroll x, lastScroll: ",
              lastScrollLeft,
              " documentScrollNow",
              documentScrollLeft
            );
            lastScrollLeft = documentScrollLeft;
          }

          ticking = false;
        });
        ticking = true;
      }
    };
    window.addEventListener("scroll", onScroll);

    return () => {
      window.removeEventListener("scroll", onScroll);
    };
  }, []);

  return (
    <div className="App" style={{ width: "300vw", height: "150vh" }}>
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

From the related article, I change window.scrollLeft to window.scrollX, this has some issue. scrollLeft is for IE.

Add window.addEventListener() inside useEffect so it doesn't get runned again every state changed, and onunmount which is return () => {} callback, we remove the eventlistener.

// UPDATE

Solution for your table onScroll

codesandbox: https://codesandbox.io/s/festive-silence-xuwfl2

maybe something like this.

David Yappeter
  • 1,434
  • 3
  • 15