skip to Main Content

I’m trying to implement a debounce function using closure with typescript React.
The problem is that it seems it’s made a new reference of the function every time when I try to pass an event argument. So I think it has something to do with passing and executing _handleScroll… Can anyone help me?

This doesn’t work

  const _handleScroll = (e: UIEvent<HTMLElement>): (() => void) => {
    e.stopPropagation();
    let prev = Date.now();
    const debounce = 500; // 500ms
    let counter = 0;

    return () => {
      const now = Date.now();
      if (prev - now > debounce) {
        prev = now;
        setScrollHeight(e.currentTarget.scrollTop);
      }
      ++counter;
      console.log("@@@", { now, prev, counter }); // result: counter: 1, 1, 1,...
    };
  };

...

    <div
      className="h-full overflow-y-auto"
      onScroll={(e) => _handleScroll(e)()}
    >

...

But this works


  const _handleScroll = (): (() => void) => {
    // e.stopPropagation();
    let prev = Date.now();
    const debounce = 500; // 500ms
    let counter = 0;

    return () => {
      const now = Date.now();
      if (prev - now > debounce) {
        prev = now;
        // setScrollHeight(e.currentTarget.scrollTop);
      }
      ++counter;
      console.log("@@@", { now, prev, counter }); // result: counter: 1, 2, 3,...
    };
  };
...

<div className="h-full overflow-y-auto" onScroll={_handleScroll()}>

...

2

Answers


  1. In second block of code that you provided when you were passing handle scroll like onScroll={_handleScroll()} you are passing returned value of that function.
    But in first block of code you’re passing onScroll={_handleScroll} you’re actually passing reference of that function. and every time your component rerenders the reference passed to the div will change
    if you want to prevent that use useCallback hook it’s similar to useEffect you wrap your function in it and pass your dependencies in [] it baiscally caches your function reference and only changes it when your dependencies change
    Hope this helps

    Login or Signup to reply.
  2. I think it would be helpful if I understand what you want.

    useRef is for avoiding re-render.

    let prev = useRef<number>();
      let height = useRef<number>(0);
      const _handleScroll = () => {
        const now = Date.now();
        const debounce = 500; // 500ms
    
        if (!prev.current) {
          ++height.current;
          prev.current = Date.now();
          setScrollHeight(e.currentTarget.scrollTop);
        }
        if (!!prev.current && now - prev.current > debounce) {
          prev.current = Date.now();
          setScrollHeight(e.currentTarget.scrollTop);
          ++height.current;
        }
      };
    
    <div className="h-full overflow-y-auto" onScroll={_handleScroll}>
    

    _handleScroll will be activated every scrolling but state updated 500ms.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search