newDev
newDev

Reputation: 107

How to refactor a list of buttons to a map function

In my hangman game, the player can click a letter(button) and the guessed letter shows if correct it is appended to the hidden word (_ _ _ _ )

but I would like to refactor a long list of buttons into a simple map function that creates a button for every letter in the array (i.e the Alphabet) ideally, the button would disappear after it has been clicked.

something like:

arr = [alphabet]
arr.map(letter=>{
return <button>{letter}</button> 
})

but I can't figure out how to convert my list into such a function

export class Input extends Component {

  handleClick = (event) => {

    if (this.props.guesses.includes(event.target.value)) {

    } else {
      this.props.makeGuess(event.target.value.toLowerCase())
    }
    // event.target.setAttribute('disabled', '')

  }

  render() {
    return (<div>

      <button onClick={this.handleClick} value="A">A</button>
      <button onClick={this.handleClick} value="B">B</button>
      <button onClick={this.handleClick} value="C">C</button>
      <button onClick={this.handleClick} value="D">D</button>
      <button onClick={this.handleClick} value="E">E</button>
      <button onClick={this.handleClick} value="F">F</button>
      <button onClick={this.handleClick} value="G">G</button>
      <button onClick={this.handleClick} value="H">H</button>
      <button onClick={this.handleClick} value="I">I</button>
      <button onClick={this.handleClick} value="J">J</button>
      <button onClick={this.handleClick} value="K">K</button>
      <button onClick={this.handleClick} value="L">L</button>
      <button onClick={this.handleClick} value="M">M</button>
      <button onClick={this.handleClick} value="N">N</button>
      <button onClick={this.handleClick} value="O">O</button>
      <button onClick={this.handleClick} value="P">P</button>
      <button onClick={this.handleClick} value="Q">Q</button>
      <button onClick={this.handleClick} value="R">R</button>
      <button onClick={this.handleClick} value="S">S</button>
      <button onClick={this.handleClick} value="T">T</button>
      <button onClick={this.handleClick} value="U">U</button>
      <button onClick={this.handleClick} value="V">V</button>
      <button onClick={this.handleClick} value="W">W</button>
      <button onClick={this.handleClick} value="X">X</button>
      <button onClick={this.handleClick} value="Y">Y</button>
      <button onClick={this.handleClick} value="Z">Z</button>
    </div>)
  }
}

Upvotes: 0

Views: 1796

Answers (4)

jsrobertouimet
jsrobertouimet

Reputation: 103

Here's an example of how to iterate over your array of letters and output a button for each of them:

export class Input extends Component {
  const handleClick = e => {
    // Your logic here...
  };

  const alphabet = [ // Letters of the alphabet... ];
  const buttons = alphabet.map(letter => (
    <button value={letter} onClick={handleClick}>
      {letter}
    </button>
  ));

  return <div>{buttons}</div>;
}

Upvotes: -1

user3210641
user3210641

Reputation: 1631

Your render method should be:

render() {
  const alphabet = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'];

  return (
    <div>
      {alphabet.map((letter, index) => <button key={} onClick={this.handleClick} value={letter}>{letter}</button>)}
    </div>
  );
}

Upvotes: 2

morsecodist
morsecodist

Reputation: 947

Here is an example of a complete component that filters the letters out:

export class Input extends Component {
  constructor() {
    super()

    this.state = {
      letters: [/* the letters */],
    }
  }


  handleClick = letter => () => {
    this.props.makeGuess(letter.toLowerCase())
    this.setState({ letters: this.state.letters.filter(l => l !== letter) })
  }

  render() {
    return (<div>
      {this.state.letters.map(letter => 
        <button key={letter} onClick=this.handleClick(letter)>{letter}</button>
      )}
    </div>
  }
}

This example initializes state with all of the letters then uses currying to create a custom click handler for each button based on the letter passed in. The functions filter out their letter and update state causing a re-render without that letter. This way there is no need to use value or deal with the event at all.

Upvotes: 0

Devan Buggay
Devan Buggay

Reputation: 2759

You can simply have a function scoped under render that creates the array of elements you want to render. Try this:

export class Input extends Component {
  render() {
    function buttonList() {
        const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
        return alphabet.map(letter => {
            return <button onClick={this.handleClick} key={letter}>{letter}</button> 
        });
    }
    return (
        <div>{buttonList()}</div>
    );
  }
}

You also need to set the key value on each of the elements or you will get a React warning.

Upvotes: 0

Related Questions