Why does only my c button work for my drum machine?

I’ve been doing a drum machine in react for the front-end library certification. I have built this codepen for my project. I have a class App where I wait for the component to mount, add event listeners and define all the functions for the drum machine. I thought I was calling the playSound function with each key that is pressed but it is only working(playing the sound) with the c key. I don’t know why it’s only working on the the c key any help is appreciated. When I inspect it the state is getting set when the keys are pressed.

let sounds = {
  q: "https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3",
  w: "https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3",
  e: "https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3",
  a: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3',
  s: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3',
  d: 'https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3',
  z: 'https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3',
  x: 'https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3',
  c: 'https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3' 
}
let names = {
  q: "Heater-1",
  w: "Heater-2",
  e: "Heater-3",
  a: 'Heater-4_1',
  s: 'Heater-6',
  d: 'Dsc_Oh',
  z: 'Kick_n_Hat',
  x: 'RP4_KICK_1',
  c: 'Cev_H2' 
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      display: "display",
      key: ""
    }
  }
  
  
  componentDidMount () {
    document.addEventListener("keydown", this.handleKey)
  }
  
  handleKey = e => {
    if (sounds.hasOwnProperty(e.key.toLowerCase())) {
      let key = e.key.toLowerCase();
      this.setState({
        key: key
      })
      this.playSound(key)
      this.updateDisplay(key)
    }
    
  }
  playSound = key => {
    console.log(`this is the key in play sound`, key)
    let sound = document.querySelector(`audio[data-key="${key}"`);
    console.log(sound)
    sound.play()    
  }
  updateDisplay = key => {
    this.setState({
      display: names[key]
    })
    console.log(this.state)
  }
  
  render () {
    return (
    <div id="drum-machine">
        <h1>YOU SEE MEEEE!??</h1>
      <p>Word I should really see some words here  up</p>
        <Display display={this.state.display} sound={this.state.key} key={this.state.key}/>
    </div>
    )
  }
}

const Display = (props) => {
  let buttons = [];
  for (var key in sounds) {
    buttons.push({key: sounds[key], name: names[key], id: key})
  }
  console.log(props)
  console.log(buttons)
  return (
  <div>
    <input value={props.display} />
      {buttons.map(obj => {
        return (
          <div>
          <button id={obj.name} 
            className="drum-pad"
            src={obj.key}
            > {obj.id} </button>
          <audio className="clip" id={key} data-key={key} src={obj.key}> </audio>
            </div>
        )
      })}
  </div>
  )
}

const Buttons = (props) => {
  
  return (
    <div className="drum-pad">
      
    </div>
  )
}




ReactDOM.render(<App />,document.getElementById('root'));

because of this line here

for (var key in sounds)

By using var you have scoped the variable to the entire render function, and then here:

<audio className="clip" id={key} data-key={key} src={obj.key}> </audio>

It takes the last value of key in the loop and attaches it to data.key, so, first

scope key to the loop block

for (const key in sounds)

And then use obj.id since that is where your sound letters are for the data-key attribute

<audio className="clip" id={obj.id} data-key={obj.id} src={obj.key}> </audio>
1 Like