如何在多个React Redux组件中使用requestAnimationFrame实现gameloop? [英] How to implement a gameloop with requestAnimationFrame across multiple React Redux components?

查看:119
本文介绍了如何在多个React Redux组件中使用requestAnimationFrame实现gameloop?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

挣扎着想出最好的方法。我可以使用 requestAnimationFrame 的递归调用来进行游戏循环:

  export interface Props {
name:string;
积分:数量;
onIncrement?:()=>无效;
onDecrement?:()=>无效;
}

class Hello扩展React.Component< Props,object> {

构造函数(道具:道具){
super(道具);
}

render(){
const {name,points,onIncrement,onDecrement} = this.props;

return(
< div className =hello>
< div className =greeting>
Hello {name + points}
< / div>
< button onClick = {onDecrement}> - < / button>
< button onClick = {onIncrement}> +< / button>
< / div>
);
}

componentDidMount(){
this.tick();
}

tick =()=> {
this.props.onIncrement();
requestAnimationFrame(this.tick)
}

}

但如果我想在每一帧上做什么:




  • 要做X的组件1

  • 组件2做Y

  • 组件3做Z



我可以在每个组件中有另一个循环但是,我的理解是让多个 requestAnimationFrame 循环进行并且这是一个重要的性能影响是不好的做法。



所以我在这里迷路了。如何让另一个组件使用相同的循环? (如果这是最好的方法!)

解决方案

您需要一个调用<$ c $的父组件c> requestAnimationFrame 并迭代



但是,我怀疑在一个真正的应用程序中,React有更多的更新要处理,或者在React的未来版本中有时间等功能切片,异步更新优先级......渲染实际上可能发生在不同的帧中。


Struggling to think of the best way to go about it. I can use a recursive call with requestAnimationFrame to have a game loop:

export interface Props {
    name: string;
    points: number;
    onIncrement?: () => void;
    onDecrement?: () => void;
}

class Hello extends React.Component<Props, object> {

    constructor(props: Props) {
        super(props);
    }

    render() {
        const { name, points, onIncrement, onDecrement } = this.props;

        return (
            <div className="hello">
                <div className="greeting">
                    Hello {name + points}
                </div>
                <button onClick={onDecrement}>-</button>
                <button onClick={onIncrement}>+</button>
            </div>
        );
    }

    componentDidMount() {
        this.tick();
    }

    tick = () => {
        this.props.onIncrement();
        requestAnimationFrame(this.tick)
    }

}

But what if I want on each frame:

  • Component1 to do X
  • Component2 to do Y
  • Component3 to do Z

I could just have another loop in each component, however my understanding is it is bad practice to have multiple requestAnimationFrame loops going and it is a significant performance hit.

So I'm at a lost here. How can I have another component use the same loop? (If that even is the best way to go about it!)

解决方案

You need a parent component that calls requestAnimationFrame and iterates over an array of refs of the children components that need to be updated on every cycle, calling its update (or however you want to call it) method:

class ProgressBar extends React.Component {

  constructor(props) {
    super(props);
    
    this.state = {
      progress: 0,
    };
  }
  
  update() {
    this.setState((state) => ({
      progress: (state.progress + 0.5) % 100,
    }));
  }  

  render() {
    const { color } = this.props;
    const { progress } = this.state;
    
    const style = {
      background: color,
      width: `${ progress }%`,
    };
    
    return(
      <div className="progressBarWrapper">
        <div className="progressBarProgress" style={ style }></div>
      </div>
    );  
  }
}

class Main extends React.Component {

  constructor(props) {
    super(props);
    
    const progress1 = this.progress1 = React.createRef();
    const progress2 = this.progress2 = React.createRef();
    const progress3 = this.progress3 = React.createRef();
    
    this.componentsToUpdate = [progress1, progress2, progress3];
    this.animationID = null;    
  }
  
  componentDidMount() {  
    this.animationID = window.requestAnimationFrame(() => this.update());  
  }
  
  componentWillUnmount() {
    window.cancelAnimationFrame(this.animationID);
  }
  
  update() {
    this.componentsToUpdate.map(component => component.current.update());
  
    this.animationID = window.requestAnimationFrame(() => this.update());  
  }
  
  render() {
    return(
      <div>
        <ProgressBar ref={ this.progress1 } color="magenta" />
        <ProgressBar ref={ this.progress2 } color="blue" />     
        <ProgressBar ref={ this.progress3 } color="yellow" />       
      </div>
    );
  }
}

ReactDOM.render(<Main />, document.getElementById('app'));

body {
  margin: 0;
  padding: 16px;
}

.progressBarWrapper {
  position: relative;
  width: 100%;
  border: 3px solid black;
  height: 32px;
  box-sizing: border-box;
  margin-bottom: 16px;
}

.progressBarProgress {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
}

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>

Keep in mind, though, that if you are trying to do something too complex and want to hit 60 fps, React might not be the right tool to use.

Also, setState is asynchronous, so when calling it you are just pushing an update to a queue that React will process at some point, which might actually happen in the next frame or later.

I profiled this simple example to see if that was the case and it's not, actually. The updates are added to the queue (enqueueSetState), but the work is done straight away:

However, I suspect that in a real application where React has more updates to handle or in future versions of React with features like time slicing, async updates with priorities... the rendering might actually happen in a different frame.

这篇关于如何在多个React Redux组件中使用requestAnimationFrame实现gameloop?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆