React中setInterval循环触发元素点击报错问题求助
问题分析与解决
错误原因
- 元素未找到或非DOM节点:
document.getElementById("dice")可能返回null(组件未挂载/已卸载),或者返回的不是原生DOM元素(比如自定义组件Dice未将id传递给内部真实DOM节点),导致调用.click()时报错。 - 定时器未清理:组件卸载后
setInterval仍在运行,此时尝试获取已销毁的元素必然触发错误。 - useRef使用不当:直接给自定义组件
Dice加ref,默认拿不到内部DOM节点,需要组件支持forwardRef传递。
解决方案
方案1:正确使用useRef + forwardRef(推荐)
如果可以修改Dice组件,先让它支持ref传递:
// 将Dice组件改为forwardRef const Dice = React.forwardRef((props, ref) => { // 把ref绑定到内部可点击的DOM元素上 return ( <div ref={ref} id={props.id} rollingTime={props.rollingTime}> {/* 组件内部内容 */} </div> ); });
父组件中使用:
import { useEffect, useRef } from 'react'; function ParentComponent() { const diceRef = useRef(null); useEffect(() => { const timer = setInterval(() => { // 先判断ref.current存在,再执行点击 if (diceRef.current) { diceRef.current.click(); console.log("Now"); } }, 10 * 1000); // 组件卸载时清理定时器 return () => clearInterval(timer); }, []); return ( <> <Dice ref={diceRef} id="dice" rollingTime="3000" triggers={["click", "P"]} /> </> ); }
方案2:不修改Dice组件,优化getElementById逻辑
如果无法修改Dice组件,每次调用前检查元素状态,同时清理定时器:
import { useEffect } from 'react'; function ParentComponent() { useEffect(() => { const timer = setInterval(() => { const diceElement = document.getElementById("dice"); // 确保元素存在且click方法可用 if (diceElement && typeof diceElement.click === 'function') { diceElement.click(); console.log("Now"); } }, 10 * 1000); return () => clearInterval(timer); }, []); return ( <> <Dice id="dice" rollingTime="3000" triggers={["click", "P"]} /> </> ); }
额外注意点
- 确认
Dice组件确实将id="dice"绑定到了内部可点击的原生DOM元素上,否则getElementById拿到的可能是组件容器而非可点击节点。 - 若定时器逻辑依赖外部状态,需将状态加入
useEffect的依赖数组,或用useCallback包裹逻辑避免失效。
内容的提问来源于stack exchange,提问作者Publius
相关产品推荐
相关产品推荐

