【问题标题】:Self-breaking interval in React.js / router implementation of background particles animationReact.js/router实现背景粒子动画的自断区间
【发布时间】:2018-08-21 22:02:34
【问题描述】:

已解决 - 问题是使用“/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);
}

粒子.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]];
 }
}

【问题讨论】:

    标签: javascript reactjs react-router setinterval particles


    【解决方案1】:

    考虑以下更改,以尽量减少您可能对内存管理施加的负载 - 关键是避免每次动画迭代重新创建约 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();
      }
    

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

    【讨论】:

    • 感谢您的建议,我刚刚实现了它们。无论如何,主要问题仍然存在。仅在切换到“/about”或“/portfolio”路线后才会发生 - 动画速度变慢,几秒钟后几乎停止;/ 仍然找不到问题。
    • 不客气 - 您更新的代码是否生效?我有兴趣对此进行进一步调查..
    • 很高兴看到 setTimeout() 技术已经奏效 - ( github.com/kaczmarekm/portfolio/blob/… ) 如果您发现此答案有用,请考虑接受 :-)
    猜你喜欢
    • 2021-07-22
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多