在 typescript React 中使用带有事件参数的闭包

Using closure with event arguments in typescript React

提问人:Ikhyeon Kim 提问时间:8/7/2023 更新时间:8/11/2023 访问量:55

问:

我正在尝试使用带有打字稿 React 的闭包来实现去抖动函数。 问题是,每次我尝试传递事件参数时,它似乎都对函数进行了新的引用。所以我认为这与传球和执行有关......谁能帮我?_handleScroll

这是行不通的

  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)()}
    >

...

但这有效


  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()}>

...
JavaScript ReactJS TypeScript 闭包

评论

0赞 Humanoid Mk.12 8/7/2023
我测试了你的代码。我只是想知道代码是如何像这样工作的。如果有任何解释,也请标记我。
0赞 Ikhyeon Kim 8/7/2023
@HumanoidMk.12 所以我想在触发滚动事件时调用一些动作,但如果用户进行非常快速的滚动移动,我不想每 10 毫秒执行一次。所以我想触发这个事件,只有当它超过我的代码中设置的那个setHeight500msdebounce

答:

0赞 Eric Khosrafian 8/7/2023 #1

在传递句柄滚动时提供的第二个代码块中,就像传递该函数的返回值一样。 但是在你传递的第一个代码块中,你实际上是在传递该函数的引用每次你的组件重新渲染时,传递给 div 的引用都会改变,如果你想防止 use useCallback 钩子,它类似于 useEffect,你把你的函数包装在其中,并将你的依赖项传递到 [] 中,它基本上会缓存你的函数引用,并且只在你的依赖项发生变化时才改变它 希望这会有所帮助onScroll={_handleScroll()}onScroll={_handleScroll}

评论

0赞 Ikhyeon Kim 8/7/2023
不幸的是,使用给了我相同的结果:/useCallback
1赞 Eric Khosrafian 8/7/2023
我认为您的问题是,当此组件重新呈现时,您会丢失 scrollTop 值,对吗?如果这是您的问题,您可以将整个组件包装在 useMemo 中,我遇到了类似的问题,我正在放大图表并且父重新渲染正在重置我的缩放 useMemo 修复了它
1赞 Humanoid Mk.12 8/7/2023 #2

我想如果我了解你想要什么会很有帮助。

useRef 用于避免重新渲染。

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将在每次滚动时激活,但状态更新了 500 毫秒。

评论

0赞 Ikhyeon Kim 8/7/2023
最初我实际使用过,正如你所写的那样,它工作正常。但我只想尝试关闭,但感谢您的帮助!useRefuseRef