如何在多个React Redux组件中使用requestAnimationFrame实现gameloop? [英] How to implement a gameloop with requestAnimationFrame across multiple React Redux components?
问题描述
挣扎着想出最好的方法。我可以使用 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屋!