在React.js/路由器实现背景粒子动画的自断区间

Self-breaking interval in React.js / router implementation of background particles animation

已解决 - 问题是容器中使用“/about”和“/portfolio”路径呈现的 setInterval 方法 - 它使动画滞后

https://github.com/kaczmarekm/portfolio - 完整的应用程序代码

http://users.pja.edu.pl/~s17335/portfolio/ - 应用程序 - 观察粒子动画如何在单击导航按钮更改页面后开始滞后、减慢和停止 - 它在几秒钟后发生,它并没有完全停止 - 它改变颜色是由于SetParticleColor() 函数,但是有很大的延迟,就像间隔设置的时间比 10ms 长得多

问题是我不知道为什么会这样,所以希望有人能找到来源。

代码:

App.js

export default class App extends Component {

  constructor(){
    super();
    this.state = {
        particleInterval: null
    }
  }

  componentWillMount() {
    InitCanvas();
    Paint();
  }

  componentDidMount(){
    this.setState({
        particleInterval: setInterval(() => 
            requestAnimationFrame(Particles), 10)
    })
  }

  render() {
    return (
        <Router>
            <div>
                <NavigationContainer/>
                <Switch>
                   <Route path="/home" component={HomeContainer}/>
                   <Route path="/about" component={AboutContainer}/>
                   <Route path="/portfolio" component={PortfolioContainer}/>
                   <Route path="/contact" component={ContactContainer}/>
                   <Route path="*" component={EntryPageContainer}/>
                </Switch>
            </div>
        </Router>
    );
  }
}

InitCanvas.js

export function InitCanvas() {
  const rootWidth = window.innerWidth;
  const rootHeight = window.innerHeight;

  const canvas = document.createElement('canvas');
  canvas.id = 'canvas';
  canvas.width = rootWidth;
  canvas.height = rootHeight;
  canvas.style.zIndex = '-1';
  canvas.style.position = 'absolute';
  canvas.style.margin = '0';
  canvas.style.padding = '0';
  canvas.style.display = 'block';

  const root = document.getElementById('root');
  root.appendChild(canvas);
}

Particles.js

import { ParticleArray } from "../../Constants/ParticleArray";
import { SetParticleColor } from "./SetParticleColor";

const rootWidth = window.innerWidth;
const rootHeight = window.innerHeight;

 for (let i = 0; i < 500; i++) {
  let moveX = Math.random() - 0.5;
  let moveY = Math.random() - 0.5;   
  ParticleArray[i] = Math.random()*rootWidth, Math.random()*rootWidth,  
                     moveX,moveY];
 }

 export function Particles() {

   const canvas = document.getElementById('canvas');
   const ctx = canvas.getContext('2d');

   ctx.clearRect(0, 0, rootWidth, rootHeight);

   for (let i = 0; i < 500; i++) {
     let centerX = ParticleArray[i][0];
     let centerY = ParticleArray[i][1];
     let moveX = ParticleArray[i][2];
     let moveY = ParticleArray[i][3];
     let radius = 2;

     ctx.beginPath();
     ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
     ctx.fillStyle = SetParticleColor();
     ctx.fill();

     centerX += moveX;
     centerY += moveY;

     if(centerX >= rootWidth || centerX <= 0 || centerY >= rootHeight || 
        centerY <= 0){
         centerX = Math.random() * rootWidth;
         centerY = Math.random() * rootHeight;
     }

     ParticleArray[i] = [centerX, centerY, ParticleArray[i][2], 
     ParticleArray[i][3]];
 }
}

考虑以下更改以最大程度地减少您可能对内存管理施加的负载 - 关键是要避免每次动画迭代重新创建约 500 个粒子对象,如下所示。

还要考虑颜色结果的重用,以提供一些额外的性能提升(取决于 SetParticleColor() 中发生的计算):

/* Avoid calling for each particle seeing the color is the same
*/
var currentColor = SetParticleColor();

for (let i = 0; i < 500; i++) {

     /* Consider extracting the current particle, and working with it
        as shown below
     */
     let particle = ParticleArray[i]

     let centerX = particle[0];
     let centerY = particle[1];
     let moveX = particle[2];
     let moveY = particle[3];
     let radius = 2;

     ctx.beginPath();
     ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
     ctx.fillStyle = currentColor;
     ctx.fill();

     centerX += moveX;
     centerY += moveY;

     if(centerX >= rootWidth || centerX <= 0 || centerY >= rootHeight || 
        centerY <= 0){
         centerX = Math.random() * rootWidth;
         centerY = Math.random() * rootHeight;
     }

     /* Mutate the existing particle in your particles array rather
        than recreating a new replacement particle for every iteration
     */
     particle[0] = centerX
     particle[1] = centerY
     particle[2] = moveX
     particle[3] = moveY
 }

我还建议使用 setTimeout 而不是 setInterval 来更新动画,同时对动画循环进行以下修改。 setInterval 将在您设置的时间间隔内重新运行,即使间隔任务尚未完成,也会重新运行。这意味着如果先前的间隔任务尚未完成,则后续任务有可能在执行中重叠 - 在这样的动画中,这将是有问题的。考虑对 componentDidMount 的以下更改:

componentDidMount(){

    // Render frame itteration
    const renderFrame = () => {

      // Request a re-render
      requestAnimationFrame(Particles)

      // Sechedule the next renderFrame when the
      // browser is ready
      setTimeout(() => renderFrame(), 10)
    }

    renderFrame();
  }

希望对您有所帮助(以及不错的投资组合网站)! :-)