SetInterval "Stacking" 相互叠加

SetInterval "Stacking" on top of each other

我正在处理这个使用 setInterval 的项目,但我在理解 setInterval 的工作原理时遇到了一些问题。我遇到的问题是,每次调用 setInterval 时,该函数似乎都堆叠在一起,导致对象快速出现多次。我不确定在这种情况下我做错了什么。谁能帮帮我谢谢。

const [hit, setHit] = useState(0)
const [count, setCount] = useState(0)
var timer = null
var funcCalls = 0
const hitSound = new Audio("/hit.wav")
useEffect(()=>{
    timer = setInterval(moveSquare, 2000)
},[])
function handleHit(){
    hitSound.play()
    setHit(hit+1)
    resetSquare()
}
function resetSquare(){
    clearInterval(timer)
    moveSquare()
    timer = setInterval(moveSquare, 2000)
}
function moveSquare(){
    const gameContainer = document.getElementById("game-container")
    const height = gameContainer.offsetHeight
    const width = gameContainer.offsetWidth
    const square = document.getElementById("square")
    square.style.top = (Math.random() * (height - 100)) + "px";
    square.style.left = (Math.random() * (width - 100)) + "px";
}
return (
    <>
    <section className='game-section'>
        <div className='counter'>
            {hit}
            {count}
        </div>
        <div className='game-container' id = "game-container">
            <div className="square" id = "square" onClick={handleHit}></div>
        </div>
    </section>
    </>
)

这是因为 timer 值未跨渲染保存,因此您无法取消它。

var timer = null // <-- no
const [timer, setTimer] = useState(null) // <-- yes
...
// later in useEffect() and resetSquare()
// save the timer using setTimer(timer)

原因在别处:您的组件(and/or 及其父组件)已重新创建。一般来说,只有几个原因,但很难在不调试的情况下指向特定的代码行:

  • 条件渲染(例如在请求期间和在渲染元素后再次显示微调器)
  • 或提供不同的key道具
  • 或者你错误地将组件声明(函数或 class 或包装到 HOC 中)放在其他组件的渲染代码中,每次重新渲染父组件时,组件的声明都会变得引用不同

另一个根本原因:您的 useEffect 没有清理。虽然它应该。即使没有第一个原因,你也不会有多个并发计时器,但你仍然会有在你离开时不会停止的计时器。

useEffect(()=>{
    timer = setInterval(moveSquare, 2000)
    return () => clearInterval(timer);
},[])

官方文档中有关清理的更多信息:https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup