验证码:
export const HomePage = (): JSX.Element => {
const refContainer = useRef<HTMLDivElement>(null);
const [scrollY, setScrollY] = useState<number>(0);
const { current: elContainer } = refContainer;
const handleScroll = useCallback(() => {
if (elContainer) setScrollY(elContainer.scrollTop);
}, []);
useEffect(() => {
document.addEventListener("scroll", handleScroll, { passive: true });
return () => removeEventListener("scroll", handleScroll);
}, [handleScroll]);
return (
<div className="pageScreen overflow-scroll" ref={refContainer}>
<Works scrollY={scrollY} />
</div>
);
};
ScrollY状态不会改变,因为elContainer为null。我如何解决这个问题?谢谢。
3条答案
按热度按时间zzlelutf1#
在第一次渲染时,您从ref中提取
.current
属性,并将其保存在变量elContainer
中。此值为null,因为页面上还没有任何内容。由于您只设置了一次scroll事件,因此handle scroll将永远使用此null值。相反,在调用handleScroll之前不要访问
.current
。这样,第一次渲染就已经完成了,并且refContainer.current已经被变异为具有以下元素:uurv41yg2#
这应该行得通:
总的来说,建议的代码更简洁,更易读,更可靠。它使用
FC
类型来定义组件,这是FunctionComponent
的简写。它使用getBoundingClientRect
方法来获取滚动位置,这比使用scrollTop
更准确。并且它使用document.removeEventListener
在卸载时删除事件侦听器,其更具体且不易出错。wgeznvg73#
useCallback
的使用使滚动处理程序记忆,导致它引用旧值elContainer
,特别是当它在初始呈现时是null
时。此外,元素的
scrollTop
仅在滚动元素本身的内容时发生变化,而不是整个文档。因此,scroll
事件处理程序应该附加到div
,这样可以大大简化代码,如下所示:需要注意的是,要使事件工作,
div
本身需要能够滚动,而不是文档,因此您还需要使用overflow: auto
和max-height
来设置div
的样式。这是一个CodeSandbox demo的行动。