2 回答

TA贡献1815条经验 获得超6个赞
正如您在评论中提到的,window.addEventListener("scroll", runOnScroll)事件监听器位于返回函数之前,因此将配置多个监听器,因为 React 将在每次重新渲染时运行函数体。
您需要在挂钩中添加事件侦听器useEffect,并在组件卸载时删除/清理侦听器。
在给定的代码中,事件侦听器在每个渲染上执行,因此将配置多个侦听器。
解决方案:
您可以在钩子中添加侦听器useEffect并在回调中删除侦听器useEffect,并传递一个空数组作为依赖项(仅运行钩子一次),使用这种方法将只有一个侦听器。
const someComponent = function () {
const [navbarBg, setNavbarBg] = useState(style_buttons)
useEffect(() => {
window.addEventListener("scroll", runOnScroll)
return () => {
window.removeEventListener("scroll", runOnScroll);
}
},[]);
function runOnScroll() {
const scrolled = window.scrollY
if (scrolled > 600 && scrolled < 650) {
setNavbarBg(style_project1)
}
}
return (
<>
</>
)
}

TA贡献1111条经验 获得超0个赞
您当前的问题是每次渲染组件时都添加一个新的滚动事件侦听器。因此,在第一次渲染之后,您将获得 1 个事件侦听器,在第二次渲染之后,您将获得 2 个事件侦听器,在第三次渲染之后,您将获得 3 个事件侦听器,等等。这基本上是内存泄漏,因为它们永远不会被删除。
通过使用,useState
您可以控制添加事件处理程序的频率,但更重要的是您可以从useEffect
.
所有对回调本身中未定义的变量的引用都应添加到依赖项列表中( 的第二个数组参数useState
)。除非保证这些变量的身份是稳定的(对象/值保持不变)。
const [navbarBg, setNavbarBg] = useState(style_buttons)
useState(() => {
function runOnScroll() {
const scrolled = window.scrollY;
if (scrolled > 600 && scrolled < 650) {
setNavbarBg(style_project1);
}
}
window.addEventListener("scroll", runOnScroll);
return () => window.removeEventListener("scroll", runOnScroll);
}, [style_project1]);
由于我们知道window
并且setNavbarBg
永远不会改变,因此可以将它们排除在依赖项列表之外。但是,由于您没有提供任何有关style_project1
我添加的信息,只是为了确定一下。如果您知道这将始终保存相同的对象/值,您可以将依赖项列表更改为[]
.
如果您不指定依赖项列表,事情仍然有效,但回调将在每次渲染后执行。这意味着每次渲染组件时,都会删除先前的滚动事件并添加新的滚动事件。通过添加依赖项列表,只有当列表中的值发生更改时,它才会重新运行(并预先清理)。这应该更加罕见,从而获得更好的性能。
添加回答
举报