React Native定时渲染问题

4
我刚刚遇到了我的应用程序的性能问题。我正试图创建一个游戏循环,使用 setInterval()函数并使用 this.forceUpdate()不断重新渲染我的游戏。我还尝试使用 this.setState()重新渲染但感觉效果相同。现在,在我的游戏循环中,我不断更新蓝色正方形(视图)的y位置。它会动,但有些卡顿。
我将 setInterval()函数的间隔设置为1000/60来模拟60FPS,但在我的应用程序中,它感觉像20。我尝试将间隔设置为1,这样就平滑了,但是经常卡顿。我会得到非常令人迷惑的微小卡顿。
我认为在我的场景中 this.forceUpdate() this.setState()不正确。
是否有其他方法可以提高性能?
更新:我也使用了 requestAnimationFrame()函数,但重新渲染时仍然出现卡顿。是否有替代 this.forceUpdate() this.setState()的方法?如何延迟 requestAnimationFrame()循环以按照60FPS运行?
谢谢您的阅读,希望我们能找到解决方案。

这就是requestAnimationFrame的作用。请参阅https://facebook.github.io/react-native/docs/timers。 - Estus Flask
@estus 我忘了提到,我也使用了requestAnimationFrame,它更流畅了,但仍然有点卡顿。有没有办法延迟requestAnimateFrame循环,使其只更新到60 FPS? - Cole Mangio
我会避免使用setInterval,因为如果之前的迭代在1000/60内没有完成,你就有可能会产生多个游戏循环迭代。 - Dacre Denny
我认为这是由于你的渲染函数引起的。它太重了。 - gu mingfeng
3个回答

4
如果您坚持认为requestAnimationFrame不适合您的应用程序/游戏循环,则建议使用setTimeout而不是setInterval。原因是,如果循环迭代需要超过16ms(1000/60)才能执行,则会出现迭代重叠-即使上一个迭代尚未完成,下一个迭代也会开始。随着时间的推移,这将引起实际问题,并可能导致卡顿。
作为替代方案,请尝试以下内容(伪代码):
doLoopIteration = () => {

    this.setState({ /* your mutation */ }, 
    () => { // This callback is fired after a component render caused by setState

        // Sechule next loop iteration in ~16ms. This approach protects
        // against the overlap issue mentioned above
        setTimeout(() => this.doLoopIteration(), 1000 / 60);
    })        
}

// Start the iteration
doLoopIteration()

如需了解更多关于setState回调的信息,请参见此文档。此外,有关基于 setInterval 的循环敏感的重叠问题的详细信息,请参阅此文档。希望这可以帮到您!


嘿,谢谢你的建议。我有机会的话会尝试你的替代方案,并确保向你更新进展情况。谢谢! - Cole Mangio
@ColeMangio 嘿,不用谢 - 是的,请告诉我你的进展如何,或者如果你需要更多帮助 :-) - Dacre Denny
嘿,我已经成功实现了你的代码,但性能方面仍然不太好。不过,setTimeout 对于延迟循环是个好主意!所以,我想到了一种“弗兰肯斯坦”式的思路,通过将 setTimeout 添加到 requestAnimationFrame 中返回到循环中来强制更新,从而调用 componentDidUpdate 函数。因此,它的性能要好得多。卡顿也少了很多。所以,感谢你建议使用 setTimeout 函数。另外,我不确定是否有其他重新渲染应用程序的方法? - Cole Mangio
嗨@ColeMangio,我的理解是setState()forceState()是触发当前组件重新渲染的唯一方法。您尝试渲染的组件有多复杂?也许您可以简化它以加快渲染速度?您可以研究https://github.com/FormidableLabs/react-game-kit,看看该React游戏库如何优化游戏循环。 - Dacre Denny
嗨!是的,我实际上已经成功地查看了游戏引擎。React-Native-Game-Engine和React-Game-Kit,我已经查看了它们的游戏循环,它们使用了requestAnimationFrame()函数和订阅者?对于订阅者数组中的每个订阅者,它都会调用一个回调函数?就像真正地调用callback.call()一样。我不太确定订阅者到底是什么... - Cole Mangio

1
如果有人想知道,你不应该在react-native的状态中编写游戏代码。相反,应该在react-native之外编写游戏代码。例如,react-native-canvas可以在没有状态的情况下绘制图形!

0

好的,我想我已经成功地根据你们的建议拼凑出了一个弗兰肯斯坦代码。 这是它。

  componentDidUpdate() {
    setTimeout(() => {
      requestAnimationFrame(this.loop);
    }, 1000/60);
  }

  loop = () => {
    this.forceUpdate();
  }

我注意到性能实际上比我尝试过的所有其他方法都要好。我认为是 setInterval/forceUpdate 太重了。是否有另一种重新渲染我的应用程序/游戏的方法?也许可以绕过重新渲染函数?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接