[英]React Redux passing multiple parameters across multiple levels of components
[英]How to implement a gameloop with requestAnimationFrame across multiple React Redux components?
努力想出最好的方法來解決它。 我可以使用帶有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)
}
}
但是如果我想要在每一幀上怎么辦:
我可以在每個組件中再有一個循環,但是我的理解是讓多個requestAnimationFrame
循環運行是不好的做法,這是一個重大的性能損失。
所以我在這里迷路了。 如何讓另一個組件使用相同的循環? (如果這是最好的方法的話!)
您需要一個父組件,它調用requestAnimationFrame
並迭代需要在每個循環中更新的子組件的refs
數組,調用其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 可能不是合適的工具。
此外, setState
是異步的,因此在調用它時,您只是將更新推送到 React 將在某個時間處理的隊列,這實際上可能發生在下一幀或之后。
我描述了這個簡單的例子,看看是否是這種情況,實際上並非如此。 更新被添加到隊列 ( enqueueSetState
),但工作會立即完成:
但是,我懷疑在 React 有更多更新要處理的實際應用程序中,或者在具有時間切片、具有優先級的異步更新等功能的 React 的未來版本中……渲染實際上可能發生在不同的幀中。
一種解決方案是將諸如callbacks
的數組定義為狀態的一部分。 在每個組件生命周期的開始,向該數組添加一個函數,該函數在每個循環中執行您想要的操作。 然后像這樣調用 rAF 循環中的每個函數:
update( performance.now())
// Update loop
function update( timestamp ) {
// Execute callback
state.callbacks.forEach( cb => cb( ...args )) // Pass frame delta, etc.
requestAnimationFrame( update )
}
通過一些工作,您可以調整這個簡單的示例,以提供一種從callbacks
刪除函數的方法,以允許按名稱或簽名從游戲循環中動態添加/減去例程。
您還可以傳遞一個包裝函數的對象,該對象還包含一個整數,您可以使用該整數按優先級對回調進行排序。
您應該創建一個運行循環的父組件,然后將其傳遞給其他組件,它應該如下所示:
<Loop>
<ComponentX loop={loop} />
<ComponentY loop={loop} />
<ComponentZ loop={loop} />
</Loop>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.