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

如何在React.js中实现鼠标点击时持续递增计数器?

解决React中鼠标点击持续递增计数器的问题

嘿,我来帮你搞定这个计数器的问题!你的代码在纯JS里能正常运行,但到React里失效,主要是踩了闭包陷阱和定时器引用管理不当这两个坑,咱们一步步来修复:

问题根源分析

  1. 未正确保存定时器引用:你代码里的timer没有用let/const声明,会变成全局变量,而且组件每次重新渲染时这个变量会被重置,导致clearTimeout无法正确定位并清除定时器。
  2. useState闭包陷阱:continuosIncerment函数里的value是组件首次渲染时捕获的初始值(0),所以每次调用setValue(value + 1)其实都是在设置0 + 1 = 1,之后就一直卡在1——因为闭包拿不到更新后的value。

修复后的代码

import React, { useState, useRef, useEffect } from "react";
import "./styles.css";

export default function App() {
  const [value, setValue] = useState(0);
  // 用useRef保存定时器引用,保证整个生命周期内引用不变
  const timerRef = useRef(null);

  const continuosIncerment = () => {
    // 函数式更新:获取最新的状态值,避开闭包陷阱
    setValue((prevValue) => prevValue + 1);
    // 将定时器ID存入ref的current属性
    timerRef.current = setTimeout(() => {
      continuosIncerment();
    }, 1000);
  };

  function timeoutClear() {
    // 从ref中取出定时器ID并清除
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      timerRef.current = null;
    }
  }

  // 组件卸载时自动清除定时器,防止内存泄漏
  useEffect(() => {
    return () => {
      timeoutClear();
    };
  }, []);

  return (
    <div className="App">
      <button
        onMouseLeave={timeoutClear}
        onMouseUp={timeoutClear}
        onMouseDown={continuosIncerment}
      >
        Increment
      </button>
      <div>Value = {value} </div>
    </div>
  );
}

关键修改点说明

  • 用useRef管理定时器:useRef的.current属性在组件整个生命周期内保持同一个引用,不会随渲染重置,这样我们能准确获取和清除定时器。
  • 函数式更新useState:setValue((prevValue) => prevValue + 1)这种写法会让React传入当前最新的状态值,不管闭包捕获的是旧值,都能正确计算下一个状态。
  • 组件卸载时清理定时器:添加useEffect的清理函数,防止组件卸载后定时器还在后台运行,造成不必要的内存泄漏。

这样修改后,你的计数器就能在鼠标按住按钮时持续递增,松开或鼠标离开按钮时立刻停止啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:47:36