Cole Mangio
Cole Mangio

Reputation: 79

React Native Rendering with SetInterval Issue

I've just stumbled upon a performance issue with my app. I'm trying to make a game loop, with a setInterval() function and re-rendering my game constantly with this.forceUpdate(). I've also tried using this.setState() to re-render but they all feel the same. Now, in my gameloop, I'm constantly updating the y position of a blue square (View). It move's but it's a bit laggy.

I set the interval of the setInterval() function to 1000/60 to simulate 60FPS, but in my app, it feels like 20. I've also tried setting the interval to 1, and it's smooth, but it stutters a lot. I get tiny lag spikes that are very disorientating.

I don't think this.forceUpdate() or this.setState() is right in my scenario.

Is there another way I could do this to make the performance better?

UPDATE: I have used the requestAnimationFrame() function as well but it still stutters on re-render. Is there an alternative to this.forceUpdate() or this.setState()? And how would I delay the requestAnimationFrame() loop so it goes off at 60FPS?

Thanks for reading and I hope we find a solution.

Upvotes: 4

Views: 5021

Answers (3)

Cole Mangio
Cole Mangio

Reputation: 79

If anyone wants to know, you really shouldn't be doing game code within react-native's state. Instead, write your game code outside of react-native. Example, react-native-canvas can graphically draw things without state!

Upvotes: 1

Cole Mangio
Cole Mangio

Reputation: 79

Okay i think i've managed to make a frankenstein code from your guys's suggestions. Here it is.

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

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

I've noticed that the performance was actually better then all other methods i've tried. I think it's the setInterval/forceUpdate thats too heavy. Is there another method of re-rendering my app/game? Perhaps bypassing re-render functions?

Upvotes: 0

Dacre Denny
Dacre Denny

Reputation: 30360

If you're adamant that requestAnimationFrame is not a good fit for your app/game loop, I would suggest using setTimeout over setInterval. The reason is, if a loop iteration takes longer than 16ms (1000/60) to execute, then you'll get iteration overlap - another iteration will start, even if the prior hasn't completed. Over time, this will cause real problems and can be a cause of stuttering.

As an alternative, try the following (pseudo code):

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()

For more on the setState callback, see this documentation. Also, see this documentation for details on the overlap problem that setInterval based loops are sensitive to. Hope that helps!

Upvotes: 4

Related Questions