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
我添加的信息,只是為了確定一下。如果您知道這將始終保存相同的對象/值,您可以將依賴項列表更改為[]
.
如果您不指定依賴項列表,事情仍然有效,但回調將在每次渲染后執行。這意味著每次渲染組件時,都會刪除先前的滾動事件并添加新的滾動事件。通過添加依賴項列表,只有當列表中的值發生更改時,它才會重新運行(并預先清理)。這應該更加罕見,從而獲得更好的性能。
添加回答
舉報