在useEffect使用setInterval引起的问题「无缝列表滚动例子」

需求📢:使列表无缝滚动,采用改变marginTop来实现滚动,还没写完就就出问题了

📍 代码如图所示, top值始终为0

在这里插入图片描述

❓:起初一头钻进了为什么setTop没生效,不明白为什么top一直为0,为什么setTop会没有生效?(心里暗暗想着一定是涉及到了js什么执行机制,只是我无法理清😵,好菜啊)
🤔:后来在useEffect中添加top依赖,由此top的值变化了。
🤔:对于图上代码分析下我当时的理解思路 ➡ 执行到useEffect的时候,开始第一次执行setScroll函数,top为0,nextTop为-5,执行到setTop后,top值更新为-5; 30ms后再执行setScroll,理所当然觉得第二次拿到的值是top的最新值。但结果不是,沉思…依稀记得,以前也是这么写的,咋就不对呢
🧐:百度去…

📍 闭包(我没看出来我🙊)

👉 具体讲解

📍 解决方法

1️⃣ useEffect第二个参数传入top依赖
缺点:计时器重复的挂载和清除

  useEffect(() => {
    timer.current = setInterval(setScroll, 30);
    return () => {
      clearInterval(timer.current);
    };
  }, [top]);

2️⃣ 使用useRef(对象的引用),将top值赋给ref.current, setScroll中使用ref.current

  const timer: any = useRef();
  const [top, setTop] = useState<number>(0)
  const step = -5
  const count: any = useRef();  // here📌
  count.current = top  // here📌
  
  const setScroll = () => {
    const deviceScroll = document.getElementById('deviceScroll');
    if (deviceScroll) {
      const nextTop = count.current + step;  // here📌
      setTop(nextTop);
      deviceScroll.style.marginTop = `${nextTop}px`;
      console.log(nextTop, top, 'iiii');
    }
  };

📍 咱需求还是得继续完成(换成使用scrollTop啦)

version 1 👇

  const timer: any = useRef();

  const setScroll = () => {
    const rawElem = document.getElementById('deviceScroll');
    const cloneElm = document.getElementById('cloneElm');
    const scrollBox = document.getElementById('deviceContainer');
    if (rawElem && cloneElm && scrollBox) {
      if (cloneElm.offsetHeight - scrollBox.scrollTop <= 0) scrollBox.scrollTop -= rawElem.offsetHeight;
      else {
        scrollBox.scrollTop += 1
      }
    }
  };

  useEffect(() => {
    // 滚动
    const rawElem = document.getElementById('deviceScroll');
    const cloneElm = document.getElementById('cloneElm');
    if (cloneElm && rawElem) {
      cloneElm.innerHTML = rawElem.innerHTML;
    }
    timer.current = setInterval(setScroll, 30);
    return () => {
      clearInterval(timer.current);
    };
  }, []);

version 2 👇

import { useEffect, useRef } from 'react';

type ElmType = {
  raw: string;
  clone: string;
  box: string;
};

const useScroll = (speed = 30, elm: ElmType, deps = []) => {
  const timer: any = useRef();
  const { raw, clone, box } = elm;

  const setScroll = () => {
    const rawElem = document.getElementById(raw);
    const cloneElm = document.getElementById(clone);
    const scrollBox = document.getElementById(box);
    // 向上无缝滚动
    if (rawElem && cloneElm && scrollBox) {
      if (cloneElm.offsetHeight - scrollBox.scrollTop <= 0)
        scrollBox.scrollTop -= rawElem.offsetHeight;
      else {
        // ⚠ 发现scrollTop + 1有时候不起作用,不会滚动,可以每次scrollTop + 2, 步数大于1就会生效
        scrollBox.scrollTop += 1;
      }
    }
    // 向左无缝滚动
    // if (rawElem && cloneElm && scrollBox) {
    //   if (cloneElm.offsetWidth - scrollBox.scrollLeft <= 0) {
    //     scrollBox.scrollLeft -= rawElem.offsetWidth;
    //   } else {
    //     scrollBox.scrollLeft += 2;
    //   }
    // }
  };

  useEffect(() => {
    if (timer.current) clearInterval(timer.current);
    const rawElem = document.getElementById(raw);
    const cloneElm = document.getElementById(clone);

    if (cloneElm && rawElem) {
      cloneElm.innerHTML = rawElem.innerHTML;
    }
    timer.current = setInterval(setScroll, speed);
    return () => {
      clearInterval(timer.current);
    };
  }, deps);
};

export default useScroll;
图示rawElem cloneElm scrollBox 元素,scrollBox样式只需写明宽高和overflow:hidden

![在这里插入图片描述](https://img-blog.csdnimg.cn/f5f63bd52c454ec888a0bd9859b3cb4b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值