努力思考最好的解决办法。我可以使用递归调用requestAnimationFrame
有一个游戏循环:
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)
}
}
但是如果我想要每一帧怎么办:
- 组件 1 执行 X
- 组件 2 执行 Y
- Component3 做 Z
我可以在每个组件中再有一个循环,但是我的理解是,有多个循环是不好的做法requestAnimationFrame
循环进行,这对性能有很大影响。
所以我在这里迷路了。如何让另一个组件使用相同的循环? (如果这是最好的方法的话!)
您需要一个调用的父组件requestAnimationFrame
并迭代数组refs https://reactjs.org/docs/refs-and-the-dom.html需要在每个周期更新的子组件的数量,调用其update
(或者你想怎么称呼它)方法:
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>
但请记住,如果您尝试做的事情过于复杂并且想要击中60 fps
,React 可能不是合适的工具。
Also, setState是异步的 https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3,因此在调用它时,您只是将更新推送到 React 将在某个时刻处理的队列,这实际上可能会在下一帧或更晚的时间发生。
我分析了这个简单的例子,看看情况是否如此,实际上并非如此。更新被添加到队列中(enqueueSetState
),但工作立即完成:
然而,我怀疑在实际应用程序中,React 有更多更新需要处理,或者在 React 的未来版本中,具有时间切片、具有优先级的异步更新等功能……渲染实际上可能发生在不同的帧中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)