首页 > 其他分享 >如何正确搭配使用 useEffect 与 setInterval

如何正确搭配使用 useEffect 与 setInterval

时间:2022-11-24 13:55:53浏览次数:36  
标签:positionY return setPositionY setInterval App 搭配 useEffect

先说一下useEffect的return回调,会在当前useEffect执行完毕后return一次。这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。

背景
useEffect 看似很简单,其实不然。由于没有理解 useEffect 的工作原理,我被狠狠坑了一回。

事情是这样的:我想实现一个很简单的“物体下落”效果:

物体的垂直位置用 positionY 这个 state 来表示,从上往下计算, positionY 越大就离屏幕顶端越远;
设置一个 setInterval,每隔一小段时间(30 ms)就增加 positionY,然后基于 positionY渲染物体,从而实现“物体下落”的效果;
看似非常简单,但遇到了意想不到的困难!

失败的尝试
我想,既然 setInterval 中的函数每隔一段时间就会触发,那么 setInterval 显然只需要运行一次就可以了!

众所周知,只运行一次函数的方式就是使用第二个参数为空数组的 useEffect 钩子。于是我写出了下面这个版本的代码:

function App() {
  const [positionY, setPositionY] = useState(0)

  useEffect(() => {
    timer = setInterval(() => {
      // 落到屏幕下方时停止下落
      if (positionY < WINDOW_HEIGHT) {
        setPositionY(positionY + 5)
      }
    }, 30)
    
    return () => {
        clearInterval(timer);
    };
  }, []);

  return (
      // 略
}

 

结果一运行我就傻了:物体根本没在动!准确地说,只是微微动了一下,之后就一直静止不懂了

哪里出错了?
为什么上面那样写会失败?后来终于找到了原因:

第一次运行 App() 时,useEffect 被运行,设置了 setInterval,并且 setInterval 也的确触发了 setPositionY(positionY + 5),因此物体才会有最开始的“微微一动”;
但当 positionY 更新之后,React 会用更新之后的 state 重新调用 App() ,但这次 useEffect 中的函数就不会运行了;
所导致的结果就是:setInterval 中的函数拿到的始终都是 positionY 的初始值。

为什么会这样?因为 setInterval 是在第一次运行 App() 时被创建的,那个 App() 里的 positionY 从未改变。

更新之后的 positionY 的确被用来第二次运行 App() 了,但第二次运行 App() 又不会运行 setInterval 了。

真是意想不到啊!

 

正确写法
至少有两种正确写法,示例如下。

方法一
第一种方法是:

在每次 positionY 改变时都执行 useEffect,使用最新的 positionY 来创建一个新的 setInterval;
与此同时,之前的 setInterval 会被自动清除,同时只会有一个 setInterval 计时器;
示例如下:

function App() {
  const [positionY, setPositionY] = useState(0)

  useEffect(() => {
    timer = setInterval(() => {
      if (positionY < WINDOW_HEIGHT) {
        setPositionY(positionY + 5)
      }
    }, 30)
    
    return () => {
        // 每次执行新的 useEffect 时,之前的 useEffect 会被清理
        // 这个函数会被调用,从而清除之前的 setInterval 计时器
        clearInterval(timer);
    };
  }, [positionY]); // 这样保证了每次 positionY 改变时,useEffect 都会执行

  return (
      // 略
}

 

方法二

第二个方法是:

  • setState 可以接受一个函数,该函数的第一个参数即是最新的 state。通过这种方法可以确保拿到最新的 state;

示例如下:

function App() {
  const [positionY, setPositionY] = useState(0)

  useEffect(() => {
    timer = setInterval(() => {
      // 这样能保证拿到最新的 positionY
      setPositionY(oldVal => {
        if (oldVal < WINDOW_HEIGHT) {
          return oldVal + 5
        }
        return oldVal
      })
    }, 30)
    
    return () => {
        clearInterval(timer);
    };
  }, []); // 只需要执行一次 useEffect 即可

  return (
  	// 略
}

  

 

标签:positionY,return,setPositionY,setInterval,App,搭配,useEffect
From: https://www.cnblogs.com/ranyonsue/p/16921628.html

相关文章

  • 衣服搭配技巧
    衬衫     比较合身的尺寸是       优衣库:XL180-108B  注意不要在优衣库买纯棉的衣服,不是很抗皱,穿上半天就特别特别皱了衬衫选购技巧:衣领:扣......
  • 配置实现-自创html生成模板搭配xml获取数据无需写代码实现静态网站
    自创html生成模板搭配xml获取数据无需写代码实现静态网站实际项目:老干部和九重阳网站欢迎访问http://www.laoganbu.orghttp://www.9chongyang.com实现思路:html界面采用自......
  • React-useEffect轮播
    第零步:导入importReact,{useState,useEffect}from"react"第一步:创建函数组件:exportdefaultfunctionBanner(){第二步:改变状态:const[n,setN]=useState(0)/......
  • 搭配Jenkins使用的服务器部署备份升级脚本
    简介主要搭配Jenkins使用,Jenkins将编译好的二进制文件上传至服务器指定文件夹中,然后执行该脚本进行原有程序备份并替换为新版程序。参数说明backupList需要备份的文件......
  • reactHooks_useEffect
    当在直接在组件内使用setState时,会产生“渲染次数过多”的错误例如:constA=()=>{  const[num,setNum]=useState(1);  setNum(1);  return(<>{num}</>)......
  • P1455 搭配购买
    ​​传送门​​思路:用并查集将相同的云朵化为一个集合,并将一个集合内的所有云朵看作一个整体,最后用01背包得到答案。#include<bits/stdc++.h>usingnamespacestd;typedef......
  • vue2搭配vue-router3真正可用不报错的写法格式
    这里要吐槽下vue和vue-router的文档教程本身前端的版本就多,版本之间还各种不兼容,用法函数还多种多样,一会这个组件一会那里是按普通渲染,简直让人不知道按哪个才是对的。然......
  • pprof搭配ceph tell命令分析ceph内存
    文章目录​​安装​​​​使用​​​​使用`cephtell`产生堆栈信息文​​​​使用`pprof`工具分析内存及`cephtell`释放内存​​​​火焰图`FlameGraph`可视化进程堆栈信......
  • setTimeout/setInterval与requestAnimationFrame的区别?
    提到setTimeout/setInterval以及requestAnimationFrame,大家的第一反应是动画相关的两个API。什么是web动画我们来谈谈什么是动画。动画其实是一种假象,是一种不连续......
  • React的useLayoutEffect和useEffect执行时机有什么不同
    我们先看下React官方文档对这两个hook的介绍,建立个整体认识useEffect(create,deps):该Hook接收一个包含命令式、且可能有副作用代码的函数。在函数组件主体内(这......