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]);
我正在尝试显示一个特定组件 - 一个“粘性 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]);