Arne
Arne

Reputation: 7

React Native for loop with Array not doing what I expected

I'm trying out some things in React Native for the first time and i'm trying to roll 3 dices (text based for now).

I'm using a for loop to go over an array of the 3 dices. However i'm only seeing one dice text being updated (the 3rd one).

Also when doing some alerts to check what's going on within that for loop, i'm seeing unexpected things? the first alert says 2, the second alert says 1 and then it usually no longer alerts, seldom it also alerts a third time with a 0.

My code so far:

(file: Game.js)

import React from 'react'
import { StyleSheet, Image, Text, View, Button } from 'react-native'

export default class Home extends React.Component {

    state = {
        dices: [null, null, null],
        rollsLeft: 3,
        keepDices: [false, false, false],
      }

    //When this component is mounted (loaded), do some defaults
    componentDidMount() {

    }

    //Roll dices
    rollDices = () => {
        for(let i = 0; i < 3; i++){
            alert('for loop at ' + i);

            //Math random to get random number from rolling the dice
            randomNumber = Math.floor(Math.random() * 6) + 1;
            //Check if the user wanted to keep a dice's value before reassigning a new value
            if(this.state.keepDices[i] === false){
                //User want to roll this dice, assign new random number to it
                //this.setState.dices[i] = randomNumber;
                let newDices = [ ...this.state.dices ];
                newDices[i] = randomNumber;
                this.setState({ dices : newDices });
            }
        }

        //Deduct 1 roll from total
        this.setState.rollsLeft--;


        //TODO: Check if rolls equals 0, then make player2 active!


    }


    render() {

        return (
          <View style={styles.container}>
            <Text> {this.state.dices[0]} ONE </Text>
            <Text> {this.state.dices[1]} TWO</Text>
            <Text> {this.state.dices[2]} THREE</Text>

            <Text>Turns left: {this.state.rollsLeft} </Text>
            <Button
              title="Roll 🎲" 
              onPress={this.rollDices} />
          </View>
        )
      }

}

const styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#fff',
      alignItems: 'center',
      justifyContent: 'center'
    },
  })

Upvotes: 0

Views: 229

Answers (2)

Arne
Arne

Reputation: 7

Together with DCQ's valuable input for async setStates bundling I also noticed that i'm always resetting the copied dice array within the for loop and thus only saving my last dice correctly.

Next up the for loop was actually counting right from 0 to 2 however the alert boxes don't interrupt the code as i'm used to in the browser therefore it looked a bit off. When doing console.log (which is also cleaner and more correct logging) I noticed things did went right there.

Upvotes: 0

DCQ
DCQ

Reputation: 111

In React Native the setState function is asynchronous.

Meaning that this.setState({ dices : newDices }); can end up setting dices to different values depending on which finishes first.

If you want to control what happens after you use setState, you can call a function after the set is done like this

this.setState({dices: newDices}, () => { 
    // Do something here. 
});

There is some really useful information on calling function after the setState here: Why is setState in reactjs Async instead of Sync?

and some good explanations of how setState in react works and how to get around it here: https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3

Upvotes: 3

Related Questions