如何在React.js中实现鼠标点击时持续递增计数器?
解决React中鼠标点击持续递增计数器的问题
嘿,我来帮你搞定这个计数器的问题!你的代码在纯JS里能正常运行,但到React里失效,主要是踩了闭包陷阱和定时器引用管理不当这两个坑,咱们一步步来修复:
问题根源分析
- 未正确保存定时器引用:你代码里的
timer没有用let/const声明,会变成全局变量,而且组件每次重新渲染时这个变量会被重置,导致clearTimeout无法正确定位并清除定时器。 - 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
相关产品推荐
相关产品推荐

