Arseniy
Arseniy

Reputation: 381

How to describe type scroll events?

I added listener on scroll, and tried to use event. How can I describe type instead of any ?

React 16.8.6 Tpescript 3.4

const Component: FC<IProps> = ({ children, scrollOffset, getScrollTop, videoListScrollUpdate }) => {
    const scroller = useRef<HTMLDivElement>(null)

    useEffect(() => {
        if (scrollOffset && scroller.current) {
            scroller.current.scrollTop = scrollOffset
            return
        }
        if (getScrollTop && scroller.current) {
            scroller.current.addEventListener('scroll', (e: any) => getScrollTop(e.target.scrollTop))
        }
    }, [])

}

Upvotes: 27

Views: 69157

Answers (5)

Aleksey Filippov
Aleksey Filippov

Reputation: 51

const onScroll = (event: UIEvent) => {
      const target = event.target as HTMLElement;

      if (target && target.scrollTop + target.clientHeight + 1 >= target.scrollHeight) {
        // do the magic
      }
    };

Upvotes: 3

Gabriel Petersson
Gabriel Petersson

Reputation: 10522

document.addEventListener("scroll", (event) => {
      const e = event as WheelEvent;
      // do stuff
});

Upvotes: 6

Daltron
Daltron

Reputation: 1866

So, I'm just going to expand on the answer from @ManjuPrabhu

Header.tsx

const Header: React.FC<IHeader> = () => {
  const [scrolling, setScrolling] = useState(false);

  useEffect(() => {
    window.addEventListener('scroll', onScroll);
    return () => {
      window.removeEventListener('scroll', onScroll);
    };
  });

  const onScroll = (e: Event) => {
    const window = e.currentTarget as Window;
    let currentPosition = window.scrollY;
    currentPosition > 0 ? setScrolling(true) : setScrolling(false);
  };

  return (
    <div
      // clsx is a npm package for conditional classes
      className={clsx('navbar sticky top-0 z-50', { 
        'shadow-2xl': scrolling,
      })}
    >
    Header content
    </div>
  );
};

tsconfig.json

"compilerOptions": {
      "target": "es5",
      "lib": [
        "dom",
        "dom.iterable",
        ...
      ],

Upvotes: -2

Manju Prabhu
Manju Prabhu

Reputation: 462

This worked for me -

//register the scroll event listener callback function
useEffect(() => {
    window.addEventListener('scroll', onScroll)
    return () => {
      window.removeEventListener('scroll', onScroll)
    }
  })
// scroll event callback function
  const onScroll = (e: Event) => {
    const window = e.currentTarget as Window
    //... rest of you function
  }

Make sure to include dom lib in tsconfig.json

"compilerOptions": {
      "target": "es5",
      "lib": [
        "dom",
        "dom.iterable",
        ...
      ],

Upvotes: 4

iamcastelli
iamcastelli

Reputation: 1774

You can use (e: React.UIEvent<HTMLElement>). Described under the UIEvent from SyntheticEvents.

That said, I would advise against using useRef within a useEffect. It's tricky to determine whether useEffect was re-called and scroller.current wasn't null (even console.log can be misleading about it).

However I would suggest to instead use the inbuilt onScroll prop on the component you are attaching the ref to, and give it a callback to handle the scroll. That way you don't need to attach it manually in the useEffect hook where you are forgetting to remove it on unmount(memory leak problems).


interface IProps {
  children: React.ReactNode;
  getScrollTop: (scrollTop: number) => whatever;
  // Your other Props
}

const ScrollComponent: React.FC<IProps> = ({
  children,
  getScrollTop,
  // Your other props
}): JSX.Element => {
  const handleScroll = (e: React.UIEvent<HTMLElement>): void => {
    e.stopPropagation() // Handy if you want to prevent event bubbling to scrollable parent
    console.log({
      event: e,
      target: e.target, // Note 1* scrollTop is undefined on e.target
      currentTarget: e.currentTarget,
      scrollTop: e.currentTarget.scrollTop,
    });

    const { scrollTop } = e.currentTarget;
    getScrollTop(scrollTop);
  };

  return (
  <div
    // I am assuming you were referencing your scroller as follows.
    // ref={scroller}
    onScroll={handleScroll} // Use the onScroll prop instead.
  >
    {children}
  </div>
  );
};

Note *1: scrollTop wont be available on e.target.scrollTop, much as you can see in in the console.log, but on e.currentTarget.scrollTop, since currentTarget calls the element on which the event handler is attached to.

Upvotes: 33

Related Questions