react利用useEffect记录用户在当前页面停留时长

项目场景:

小程序项目中需要记录用户在当前页面停留的时长,下意识想到在useState中记录一个时间戳,在useEffect中的return中获取一个时间戳,减去state中记录的时间戳,用得到的值取请求接口。

问题描述:

考虑到用户网络情况,如果用户在页面还没加载完时等不及就进行了返回操作,此时记录页面停留时长显然不太合理。所以应该在useEffect中请求成功返回后,再进行记录时间戳作为用户开始浏览的时间。

const [timestamp, setTimestamp] = useState(0);
useEffect(() => {
  ... // 执行请求
  setTimestamp(new Date().getTime());
  return () => {
    if(timestamp) { // 如果时间戳不为0 意味着是加载完成后才离开的页面
      saveTime(new Date().getTime() - timestamp);// 记录停留时长
    }
  }
},[]);// 只在初次渲染和卸载时触发

可是每当返回的时候,根本不会发送请求记录停留时长,不管当前页面是否加载完成。


原因分析:

查看react文档后意识到,当给useEffect传递数组作为第二个参数时,需要确保数组中包含了所有外部作用域中会随时间变化并且在effect(也就是传入useEffect的第一个参数)中使用的变量,否则代码会引用到先前渲染中的旧变量。

上面代码中就是没将timestamp写到useEffect的第二个参数中,所以取到的timestamp值一直为0,自然不会发送请求记录停留时长。

所以如果想在useEffect取到最新的timestamp值的话需要将timestamp写到useEffect的第二个参数中

const [timestamp, setTimestamp] = useState(0);
useEffect(() => {
  ... // 执行请求
  setTimestamp(new Date().getTime());// 改变timestamp 导致无限循环
  return () => {
    if(timestamp) {
      saveTime(new Date().getTime() - timestamp);
    }
  }
}, [timestamp]);// timestamp改变时触发

但是这样当timestamp改变时又会去重新设置timestamp的值,就会无限循环,导致报错。

解决方案:

useEffect如果要在effect中取到最新的propstate,必须得将相应的propstate传入第二个参数数组中。但是如果是取useRef创建的对象中的值,则不用将ref传入第二个参数数组,也能获取到ref中的最新值。所以可以在ref中记录时间戳。

const timestamp = useRef(0);
useEffect(() => {
  ... // 执行请求
  timestamp.current = new Date().getTime();
  return () => {
    if(timestamp.current) {
      saveTime(new Date().getTime() - timestamp.current);// 请求接口保存时长
    }
  }
}, []);

因为useRef创建的是一个普通 Javascript 对象,而且useRef会在每次渲染时返回同一个ref对象。所以总能获取到ref对象中current属性的最新值。

当然,如果在effect外部没有使用到timestamp,则不使用useRef,直接将timestamp定义在effect内部也是可以的,就像

useEffect(() => {
  ... // 执行请求
  const timestamp = new Date().getTime();
  return () => {
    if(timestamp) {
      saveTime(new Date().getTime() - timestamp);// 请求接口保存时长
    }
  }
}, []);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值