0

I am new to React and I am trying to figure out how I can shuffle an array. I have tried different way to shuffle the array but the problem is always with the length. TypeError: Cannot read property 'length' of undefined. I am not sure why this is happening or how I should deal with it in React. To me, this shouldn't be an issue with React but again I don't know. What should happen when everything works:

You click on the button 'hard' and it should render the two first elements from the array challenge, and every time you click on that button the array should be shuffled.

Do you have any idea that could help me?

This is the code:

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

let era = [
  60, 70, 80, 90, 2000
]

let genre = [
  'Rock', 'Pop', 'Jazz', 'Country'
]

let challenge = [
  'LikeElvis', 'Parent\'s favourite songs', 'too high for me'
]

class Karaoke extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      'easy': '',
      'easyChallenge': '',
      'hard': '',
      'hardChallenge': '',
      'hardEra': ''
    }
  };

  selectEasy = () => {
    let genreSelected = [];
    let challengeSelected = [];
    genreSelected.push(genre[Math.floor(Math.random() * genre.length)]);
    this.setState({"easy": genreSelected})

    challengeSelected.push(challenge[Math.floor(Math.random() * challenge.length)]);
    this.setState({"easyChallenge": challengeSelected})
  }

  selectHard = () => {
    let genreSelected = [];
    let challengeSelected = [];
    let eraSelected = [];
    genreSelected.push(genre[Math.floor(Math.random() * genre.length)]);
    eraSelected.push(era[Math.floor(Math.random() * era.length)]);

    this.setState({ "hard": genreSelected} );
    this.setState({ "hardEra": eraSelected} );
    this.setState({ "hardChallenge": challengeSelected} );

    challengeSelected.push(challenge.slice(0, 2))
    console.log(challengeSelected);
  }

  shuffle = (challenge) => {
    let i = challenge.length, temporaryValue, randomIndex;
    while (0 !== i) {
      randomIndex = Math.floor(Math.random() * i);
      i -= 1;
      temporaryValue = challenge[i];
      challenge[i] = challenge[randomIndex];
      challenge[randomIndex] = temporaryValue;
    }
    return challenge
  }

  click = () => {
    this.selectHard();
    this.shuffle();
  }

  render = () => {
    return(
      <div>
        <button onClick={this.selectEasy}>Easy</button>
        <button onClick={this.click}>Hard</button>
        <h1>the genre is {this.state.easy} </h1>
        <h1>the challenge is {this.state.easyChallenge} </h1>
        <h1>Hard mode: {this.state.hard} + {this.state.hardEra + '\'s'}</h1>
        <h1>Hard mode challenge: {this.state.hardChallenge} </h1>
      </div>
    )
  }

}


ReactDOM.render(<Karaoke />, document.getElementById('root'));
5
  • 1
    the error message is not indicating that there is a problem with the length, but rather that the object you're trying to get the length from is not an array but is undefined. Commented Nov 14, 2017 at 13:47
  • 1
    Sometimes you are using arrow functions, sometimes not. Consider unifying your code. Commented Nov 14, 2017 at 13:51
  • 1
    @GhassenLouhaichi I have seen this and tried it, but I got the same error with the length. Commented Nov 14, 2017 at 13:53
  • 1
    @Logar Why? They are global variables and component have an access to them. Anyways - shuffle = (challenge) => { remove challenge from this line and should work properly, probably. Commented Nov 14, 2017 at 14:05
  • 1
    Removed my comment as indeed it was not your problem at all. But I'm really not sure declaring let variables outside of the class to use them inside is a good idea Commented Nov 14, 2017 at 14:06

1 Answer 1

1

You are defining your suffle method expecting an argument. But then when you call it from the click method you are not providing said argument:

shuffle(challenge) {
    // ...
}

click = () => {
    // ...
    this.shuffle();
}

This will cause the declared argument to be undefined and the suffle method will not default the global challenge variable.

To solve this, you need to either remove the argument from the method defintion or pass it in the click function:

shuffle() {
    // ...
}
click = () => {
    // ...
    this.shuffle();
}

/* OR */

shuffle(challenge) {
    // ...
}
click = () => {
    // ...
    this.shuffle(challenge);
}
Sign up to request clarification or add additional context in comments.

Comments

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.