You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用useEffect、useState、useInView实现元素进入视口时数字递增效果

问题原因
  • 闭包陷阱:负责执行计数的useEffect仅依赖counting变量,仅在counting变为true时执行一次,回调内部捕获的number永远是初始值0,每次执行setNumber(number + 1)实际都是将数值设置为1,定时器后续触发时拿到的仍然是旧的number值,导致数值无法正常递增。
  • 缺少定时器清理逻辑:setInterval启动后没有在数值达到目标值、组件卸载时销毁,既会造成内存泄漏,也会导致定时器持续无意义运行。
  • 状态更新写法错误:直接使用闭包中的number变量做计算,没有使用React状态更新的函数式写法,无法拿到最新的状态值。
修复方案
import { useState, useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

function NumericIndicator(props) {
  const [number, setNumber] = useState(0);
  const [ref, inView] = useInView({
    triggerOnce: true // 配置进入视口后只触发一次,不需要重复计数可保留该配置
  });

  useEffect(() => {
    // 未进入视口或数值已达目标时不启动定时器
    if (!inView || number >= props.value) return;

    const timer = setInterval(() => {
      setNumber(prev => {
        // 函数式更新直接拿到最新的状态值,规避闭包问题
        if (prev < props.value) {
          return prev + 1;
        }
        // 达到目标值后清除定时器
        clearInterval(timer);
        return prev;
      });
    }, 50); // 调整该数值可控制计数速度,值越小速度越快

    // 依赖变化/组件卸载时自动清理定时器
    return () => clearInterval(timer);
  }, [inView, number, props.value]);

  return (
    <div ref={ref}>
      <h1>{number}</h1>
      <p>
        <small>需要实现从0递增到{props.value}的效果</small>
      </p>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者RBFraphael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 11:30:02