1

I'm trying to make a simple game: country flags are flashing one by one on the screen, and it stops on one particular flag after clicking on the button.

This is what I have so far:

import React from 'react'
import ReactDOM from 'react-dom'


// CSS styles in JavaScript Object
const buttonStyles = {
  backgroundColor: '#61dbfb',
  padding: 10,
  border: 'none',
  borderRadius: 5,
  margin: 30,
  cursor: 'pointer',
  fontSize: 18,
  color: 'white',

}
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { image: 'https://www.countryflags.io/US/shiny/64.png' }
    this.makeTimer()
  }

  makeTimer() {
    setInterval(() => {
      let countries = {
        USA: 'https://www.countryflags.io/US/shiny/64.png',
        Australia: 'https://www.countryflags.io/AU/shiny/64.png',
        "Puerto Rico": 'https://www.countryflags.io/PR/shiny/64.png'
      }
      let currentCountry = Math.floor(Math.random() * (Object.entries(countries).map(([key, value]) => <div>{key} <img alt={key} src={value}></img></div>)))
      this.setState({ currentCountry })
    }, 1000)
  }

  stopInterval = () => {
    clearInterval(this.interval);
  }
  render() {

    return (
      <div className='app'>
        <h1>where are you going on vacation?</h1>

        <div>{this.state.currentCountry}</div>
        <button style={buttonStyles} onClick={this.stopInterval}> choose country </button>

      </div>
    )
  }
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)

It does not work, all that renders is:

NaN

Before I added Math.floor(Math.random() * ...) it rendered all three flags at the same time, which is not what I want. Where is the mistake?

Also, I am not sure if the timer works correctly.

1
  • Didn't read everything, but Math.floor(Math.random()) is always zero. Commented Feb 6, 2021 at 17:15

4 Answers 4

1

You can't multiply a number (Math.random) with an array (Object.entries(countries).map).

You should create a helper function to grab a single element (or value) from an object if you're storing the flags in an object.

Also, you should never ever store JSX elements in your state. All you need is a URL, not a whole image element. You can store a random URL and update the image's src if the state is updated:

const buttonStyles = {
  backgroundColor: '#61dbfb',
  border: 'none',
  borderRadius: 5,
  color: 'white',
  cursor: 'pointer',
  fontSize: 18,
  margin: 30,
  padding: 10,
};

function randomProperty(obj) {
  const keys = Object.keys(obj);
  return obj[keys[(keys.length * Math.random()) << 0]];
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentCountry: null,
      image: 'https://flagcdn.com/w128/us.png',
    };
    this.makeTimer();
  }

  makeTimer() {
    let countries = {
      'Australia': 'https://flagcdn.com/w160/au.png',
      'Puerto Rico': 'https://flagcdn.com/w160/pr.png',
      'USA': 'https://flagcdn.com/w160/us.png',
    };

    this.interval = setInterval(() => {
      let currentCountry = randomProperty(countries);
      this.setState({ currentCountry });
    }, 1000);
  }

  stopInterval = () => {
    clearInterval(this.interval);
  };

  render() {
    return (
      <div className="app">
        <h1>Where are you going on vacation?</h1>
        <img alt="" src={this.state.currentCountry} width="80" />
        <button style={buttonStyles} onClick={this.stopInterval}>
          Choose country
        </button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

Comments

1

I got something different for you, I expect it helps you.

let countries = {
    USA: 'https://www.countryflags.io/US/shiny/64.png',
    Australia: 'https://www.countryflags.io/AU/shiny/64.png',
    'Puerto Rico': 'https://www.countryflags.io/PR/shiny/64.png',
};

//I changed the object to array for better data manipulation.
const countriesArray = Object.entries(countries).map(country => {
    return { name: country[0], flag: country[1] }
})

//Getting random country index by its length
const randomCountryIndex = Math.floor(Math.random() * countriesArray.length);

console.log("Set the current country: ", countriesArray[randomCountryIndex])
console.log("Set the random flag: ", countriesArray[randomCountryIndex].flag)

So after this you can check if user's answers match the current country on state

Comments

1

Avoid jsx in state. Refactored your Math.random() code.

import React from 'react'
import ReactDOM from 'react-dom'


const countries = [
    { name: "USA", image: 'https://www.countryflags.io/US/shiny/64.png' },
    { name: "Australia", image: 'https://www.countryflags.io/AU/shiny/64.png'},
    { name: "Puerto Rico", image: 'https://www.countryflags.io/PR/shiny/64.png' }
];
// CSS styles in JavaScript Object
const buttonStyles = {
    backgroundColor: '#61dbfb',
    padding: 10,
    border: 'none',
    borderRadius: 5,
    margin: 30,
    cursor: 'pointer',
    fontSize: 18,
    color: 'white',

}
class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = { image: 'https://www.countryflags.io/US/shiny/64.png' }
        this.makeTimer()
    }

    makeTimer() {
        this.interval = setInterval(() => {
            const countryIndex = Math.floor(Math.random() * countries.length);
            this.setState({
                image: countries[countryIndex].image
            });
        }, 1000)
    }

    stopInterval = () => {
        clearInterval(this.interval);
    }
    render() {

        return (
            <div className='app'>
                <h1>where are you going on vacation?</h1>

                <div>{this.state.currentCountry}</div>
                <button style={buttonStyles} onClick={this.stopInterval}> choose country </button>

            </div>
        )
    }
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)

Comments

-1

Math.floor(Math.random()) returns zero! use this:

Math.floor(Math.random() * 10);

1 Comment

OP didn't use Math.floor(Math.random()) in their code but Math.floor(Math.random() * somevalue);, exactly what you're suggesting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.