【问题标题】:React app does not fire off onScroll events as expectedReact 应用程序不会按预期触发 onScroll 事件
【发布时间】:2021-10-26 20:08:04
【问题描述】:

我正在尝试显示一个特定的组件 - 当页面显示它时,一个“粘性标题”片段从顶部滚动 X 个点。

我尝试使用 use-react 包中的 useWindowScroll 钩子以及下面的简短片段来执行此操作:

  const [scrollTop, setScrollTop] = useState(0);

  function setScroll() {
    console.log('setScroll');
    setScrollTop(window.pageYOffset);
    console.log(new Date().getTime());
  }

  useEffect(() => {
    function watchScroll() {
      console.log('watchScroll');
      window.addEventListener("scroll", setScroll);
    }
    watchScroll();
    return () => {
      window.removeEventListener("scroll", setScroll);
    };
  });

  console.log('scroll top:', scrollTop);

理想情况下,我们可能希望在处理每个新滚动事件之前有一点延迟,但这不是我的问题。

我希望setScroll 在我滚动时被调用,无论多少毫秒。然而,这并没有发生。事实上,我从来没有看到它被调用过。

由于它不会在适当的时候被调用,我的const shouldShowStickyHeader = scrollTop > 1000; 总是设置为false。因此,我的从未显示。我希望它在滚动到顶部距离为 1,000 时出现。

有什么问题?

我还尝试了带有效果挂钩内所有内容的版本:

  const [scrollTop, setScrollTop] = useState(0);

  useEffect(() => {
    function setScroll() {
      console.log('setScroll');
      setScrollTop(window.pageYOffset);
      console.log(new Date().getTime());
    }
    window.addEventListener("scroll", setScroll);
    return () => {
      window.removeEventListener("scroll", setScroll);
    };
  }, [scrollTop]);

我没有看到setScroll 在控制台中打印。可能是什么问题?

我用document.querySelectorAll("*").forEach(element => element.addEventListener("scroll", ({target}) => console.log(target, target?.id, target?.parent, target?.parent?.id))); 做了一个小测试。当我滚动时,确实有事件被触发。见:

<div data-testid="vdp-scroll-container" id="vdp-scroll-container" class="jsx-1959376998 vdp-scroll-container">
...
<div data-testid="vdp-scroll-container" id="vdp-scroll-container" class="jsx-1959376998 vdp-scroll-container">

我尝试将列表直接放在这个元素上:

document.getElementById('#vdp-scroll-container')?.addEventListener("scroll", setScroll);
    return () => {
      document.getElementById('#vdp-scroll-container')?.removeEventListener("scroll", setScroll);
    };

不过,我没有看到任何东西被解雇。

这个&lt;div/&gt;的样式如下:

height: 100%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll;

因此我什么也得不到吗?

【问题讨论】:

    标签: javascript reactjs browser react-hooks vertical-scrolling


    【解决方案1】:

    您应该将一个空数组作为第二个参数传递给 useEffect,以便该函数仅在组件第一次安装后才被触发。不传递第二个参数,将在每次重新渲染后触发函数,传递[scrollTop] 将在每次scrollTop 更改时触发函数。

    这样的事情应该可以工作:

      const [offset, setOffset] = React.useState(null);
      const setScroll = () => {
        setOffset(window.scrollY);
      };
    
      React.useEffect(() => {
        window.addEventListener("scroll", setScroll);
        return () => {
          window.removeEventListener("scroll", setScroll);
        };
      }, []);
    

    工作示例:https://codesandbox.io/s/zen-cdn-ll6es?file=/src/App.js

    【讨论】:

    • 我的第二个版本已经通过了 scrollTop,而不是一个空数组。
    • @IgorShmukler 当你将 scrollTop 传递给 useEffect 时,你传递给 useEffect 的函数将在每次 scrollTop 改变时被调用。因此,几乎每次调度滚动事件时,您都会添加然后删除事件侦听器。
    • 有道理。我认为你也许是对的。谢谢。
    【解决方案2】:

    将侦听器附加到窗口不起作用。但是,在我删除 height: 100% 后,我可以通过以下方式订阅滚动事件:

      const [scrollTop, setScrollTop] = useState(0);
    
      useEffect(() => {
        const setScroll = () => {
          setScrollTop(window.pageYOffset);
        };
        document.querySelector('#vdp-scroll-container')?.addEventListener("scroll", setScroll);
        return () => {
          document.querySelector('#vdp-scroll-container')?.removeEventListener("scroll", setScroll);
        };
      }, [scrollTop]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-15
      • 2021-10-22
      • 1970-01-01
      • 2013-04-29
      • 1970-01-01
      • 2016-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多