为了账号安全,请及时绑定邮箱和手机立即绑定

ReactJS setState 仅一次

ReactJS setState 仅一次

烙印99 2023-07-06 16:34:19
我正在尝试根据网页的 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 但我认为我不清楚如何使用它。有人可以帮忙吗?
查看完整描述

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 (

        <>

        </>

    )

}


查看完整回答
反对 回复 2023-07-06
?
catspeake

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我添加的信息,只是为了确定一下。如果您知道这将始终保存相同的对象/值,您可以将依赖项列表更改为[].

如果您不指定依赖项列表,事情仍然有效,但回调将在每次渲染后执行。这意味着每次渲染组件时,都会删除先前的滚动事件并添加新的滚动事件。通过添加依赖项列表,只有当列表中的值发生更改时,它才会重新运行(并预先清理)。这应该更加罕见,从而获得更好的性能。


查看完整回答
反对 回复 2023-07-06
  • 2 回答
  • 0 关注
  • 145 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信