【发布时间】:2019-11-27 01:19:59
【问题描述】:
首先,使用类组件,这可以正常工作并且不会引起任何问题。
但是,在带有钩子的功能组件中,每当我尝试从滚动事件侦听器的函数 handleScroll 设置状态时,即使我使用 debounce,我的状态也无法更新或应用程序的性能会受到严重影响。
import React, { useState, useEffect } from "react";
import debounce from "debounce";
let prevScrollY = 0;
const App = () => {
const [goingUp, setGoingUp] = useState(false);
const handleScroll = () => {
const currentScrollY = window.scrollY;
if (prevScrollY < currentScrollY && goingUp) {
debounce(() => {
setGoingUp(false);
}, 1000);
}
if (prevScrollY > currentScrollY && !goingUp) {
debounce(() => {
setGoingUp(true);
}, 1000);
}
prevScrollY = currentScrollY;
console.log(goingUp, currentScrollY);
};
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return (
<div>
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
<div style={{ background: "orange", height: 100, margin: 10 }} />
</div>
);
};
export default App;
尝试在handleScroll 函数中使用useCallback 挂钩,但没有多大帮助。
我做错了什么?如何在不影响性能的情况下从 handleScroll 设置状态?
我已经为这个问题创建了一个沙盒。
【问题讨论】:
-
您仍在为每一次去抖动创建句柄滚动。你应该记住它。您的卸载仍在调用
addEventListener而不是removeEventListener。这两者都可能导致问题:) -
@JohnRuddell 嘿,感谢您在
removeEventListener上发现错误。但是,这会导致内存泄漏,但与我要解决的性能问题无关。这只是一个错字,在原始项目中使用的是删除而不是添加,但问题仍然存在 -
不完全是,因为您可以通过简单的滚动设置数百个侦听器。这意味着每个回调都试图在每个去抖动滴答声中触发数百次。
-
@JohnRuddell 好的,但这只有在我卸载并重新安装组件数百次时才会发生(这里不是这种情况),因为当前效果仅在安装/卸载时运行。
-
是的,所以你应该记住手柄滚动。或者更好的是,不要放弃类语法,因为您已经有了一个可行的解决方案。
标签: javascript reactjs addeventlistener react-hooks