所以你的匿名函数被锁定在 的初始值上scrolling
。这就是闭包在 JS 中的工作方式,你最好找一些关于它的漂亮文章,这可能会很棘手,而且钩子严重依赖闭包。
到目前为止,这里有 3 种不同的解决方案:
1. 在每次更改时重新创建和重新注册处理程序
useEffect(() => {
const scrollHandler = () => {
if (scrolling === false) setScrolling(true);
};
window.addEventListener("scroll", scrollHandler);
return () => window.removeEventListener("scroll", scrollHandler);
}, [scrolling]);
而这条路确保您在返回的清理从功能useEffect
。这是很好的默认方法,但对于滚动它可能会影响性能,因为滚动事件触发太频繁。
2.通过引用访问数据
const scrolling = useRef(false);
useEffect(() => {
const handler = () => {
if (scrolling.current === false) scrolling.current = true;
};
window.addEventListener("scroll", handler);
return () => window.removeEventListener("scroll", handler);
}, []);
return (
<>
scrolling: {scrolling}
</>
);
缺点:更改 ref 不会触发重新渲染。所以你需要有一些其他变量来改变它触发重新渲染。
3. 使用功能版本的 setter 访问最新值
(我认为这是首选方式):
useEffect(() => {
const scrollHandler = () => {
setScrolling((currentScrolling) => {
if (!currentScrolling) return true;
return false;
});
};
window.addEventListener("scroll", scrollHandler);
return () => window.removeEventListener("scroll", scrollHandler);
}, []);
注顺便说一句,即使一次性使用效果你更好的回报清理功能反正。
PS 此外,现在您还没有设置scrolling
为false
,因此您可以摆脱 condition if(scrolling === false)
,但可以肯定的是,在现实世界中,您也可能会遇到类似的情况。