React 应用程序未按预期触发 onScroll 事件

React app does not fire off onScroll events as expected

我正在尝试显示一个特定组件 - 一个“粘性 header”片段,当显示它的页面从顶部滚动 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);
    };

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

<div/>的样式如下:

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

难道我什么都没有得到吗?

您应该将一个空数组作为第二个参数传递给 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

将侦听器附加到 window 无效。但是,在我删除 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]);