ReactJS setState 仅一次

我正在尝试根据网页的 Y 滚动位置设置导航栏背景颜色。问题是,一旦我进入要设置导航栏背景状态的 Y 坐标之间,它就不会停止设置,直到页面冻结。这是我的代码,以便更好地理解:


获取 Y 滚动位置,检查其是否在 600 和 650 之间,如果为 true,则设置导航栏背景颜色:


const [navbarBg, setNavbarBg] = useState(style_buttons)


function runOnScroll() {

  const scrolled = window.scrollY

  if (scrolled > 600 && scrolled < 650) {

    setNavbarBg(style_project1)

  }

}


window.addEventListener("scroll", runOnScroll)

即使我没有滚动并且我不知道如何打破它,它也会不断设置状态。


我尝试使用 UseEffect 但我认为我不清楚如何使用它。


有人可以帮忙吗?


烙印99
浏览 146回答 2
2回答

红糖糍粑

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

catspeake

您当前的问题是每次渲染组件时都添加一个新的滚动事件侦听器。因此,在第一次渲染之后,您将获得 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我添加的信息,只是为了确定一下。如果您知道这将始终保存相同的对象/值,您可以将依赖项列表更改为[].如果您不指定依赖项列表,事情仍然有效,但回调将在每次渲染后执行。这意味着每次渲染组件时,都会删除先前的滚动事件并添加新的滚动事件。通过添加依赖项列表,只有当列表中的值发生更改时,它才会重新运行(并预先清理)。这应该更加罕见,从而获得更好的性能。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript