查看最终实现的效果:Bouncing Balls Start。
最近在学习 2D canvas
有关知识,并参照 MDN 文档(Let's bounce some balls)使用 canvas
编写一个碰撞小球程序,在将该程序结合 React Hook 进行开发的时候遇到了一些问题,这儿将一些遇到的问题以及对应的解决方案记录一下。
cancelAnimationFrame
无法取消动画
原本的让小球动起来的部分如下,函数执行完 return
动画的 ID 并请求动画执行,继而实现动画的连续运行。通过获取到的 ID 用于后续的取消动画。
这样操作动画并不能被取消,原因在于每一次 requestAnimationFrame()
返回的值都是不一样的,仅仅保存了第一次的 id,肯定无法通过这个 id 去取消后面正在进行的动画。正确做法是需要时刻更新 id,确保在取消的时候 id 是正在进行的动画。
经过上述改造,在离开页面的时候运动会被正常的取消,避免资源未回收。
多次进入页面小球运动速度加快
原因是由于上次的 requestAnimationFrame
并没有被取消,页面离开之后画布以及创建的小球并未被销毁,再次进入页面的时候再次调用了 requestAnimationFrame
,使得 update()
函数在同一个 frame
中被执行了两次,该函数主要用于移动小球,所以产生了小球移动速度加快的情况,正常取消动画问题得以解决。
在 useEffect
中动画函数频繁被创建
创建小球比较耗费资源,如果在 useEffect
中直接创建,Next.js
会提示可以通过 useCallback
进行优化。同样的,我们进行改造。
将 memoLoop
用来保存 loop
函数返回的 start
函数,并且只有在 canvasCtx
、canvasCtx
以及 canvasCtx
变化的时候才会重新调用 loop
函数。同样的,对于 useEffect
同样进行改造。
注意在 useEffect
中使用了 memoLoop
,记得将其添加进数组中。
完整的代码在请看 这里。