React Drum Machine - I can not figure out the sound function

Hello,

I have been working on this drum machine but it seems like the sound function is not working correctly.
When I checked my code, it seems like correct src is going into the audio tag, but every button is making the same sound.

Could anyone help on this?

here is my code: https://codepen.io/eriko87/pen/vqWQmd?editors=0110

I found the solution here and was able to fix the sound issue.

my original code:
playSound(event) {
this.audio.play();
this.audio.currentTime = 0
}
changed to:
playSound(event) {
const audio = event.target.querySelector(‘audio’);
audio.play();
audio.currentTime = 0
}

That is not the React way of doing it. You should be using refs as you did in your first attempt.

Thanks for your replay. I am very new to React and not sure what is React way and I couldn’t figure out the way with refs.
Could you advice how I can make it work with refs.?
I put my original code back (the one that doens’t work) to the codepin.

The issue was:

ref = { ref => this.audio = ref}

You need to make sure the this.audio is unique for each audio element. One way of doing that is to use something already unique as a property name (i.e. key.id). You will have to remember how to assign a value to object property when the property is a variable, but I will let you figure that part out.

Once you figure out the above, the only other code sections you will need to modify is the onClick property of the button (seen below):

    const padButton = this.state.data.map((key, index)=>{
      return <div>
        <button 
          className="drum-pad"
          onClick={()=>{
            this.playSound(event); // instead of passing event, you need to pass key.id
            this.displayHandlar(event);
          }}

Then, in your playSound method, you will need to reference the key.id passed to it. Again, you will need to remember how to reference an object property when the property is a variable.

Hopefully this gives you enough information to solve it on your own.

On an unrelated note:
Your displayHandler is already using arrow function syntax. If you also make your playSound an arrow function, then you can delete the following two lines in your constructor.

this.displayHandlar = this.displayHandlar.bind(this);
this.playSound = this.playSound.bind(this);

Thank you very much for your advise!
I have been looking into this but I don’t know how to make this.audio to each audio element. Perhaps is there any material that I can read to solve this problem?

Hint: Think bracket notation instead of dot notation for accessing the this object properties.

https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-object-properties-with-variables

I changed to below but it doesn’t seem to be working.

ref = { ref => {
              uniqueid={key.id}
              this.audio[uniqueid] = ref}}

what am I missing?

Remember that you need to be creating properties on this not this.audio.

ref={ ref => this[?????] = ref }

It seems like it’s working now!
Is this correct as React way?

I changed 3 sections:

playSound(event) {
this[event].play();                  //<-----here
this[event].currentTime = 0          //<-----here
}
<button 
          className="drum-pad"
          onClick={()=>{
            this.playSound(key.id); //<-----here
            this.displayHandlar(event);
          }}
          value={key.id} 
          id={key.id}
          key={key.id}
          >
 ref = { ref => {
              this[key.id] = ref
              console.log(ref)}}

my new code is below.

const databankOne =[{
    keyTrigger: 'Q',
    id: 'Heater-1',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3'
  }, {
    keyTrigger: 'W',
    id: 'Heater-2',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3'
  }, {
    keyTrigger: 'E',
    id: 'Heater-3',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3'
  }, {
    keyTrigger: 'A',
    id: 'Heater-4',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3'
  }, {
    keyTrigger: 'S',
    id: 'Clap',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3'
  }, {
    keyTrigger: 'D',
    id: 'Open-HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3'
  }, {
    keyTrigger: 'Z',
    id: "Kick-n'-Hat",
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3'
  }, {
    keyTrigger: 'X',
    id: 'Kick',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3'
  }, {
    keyTrigger: 'C',
    id: 'Closed-HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3'
  },
];



class App extends React.Component {
  constructor(props){
    super(props);
    this.state ={
      data: databankOne,
      display: 'Loading...',
      sound:""
    };
  };
  

    playSound(event) {
this[event].play();
this[event].currentTime = 0
}

  displayHandlar = (event) => {
    this.setState ({
      display: event.target.value
    })
  };

  render() { 
 
    const padButton = this.state.data.map((key, index)=>{
      return <div>
        <button 
          className="drum-pad"
          onClick={()=>{
            this.playSound(key.id);
            this.displayHandlar(event);
          }}
          value={key.id} 
          id={key.id}
          key={key.id}
          >
          <audio 
            className="clip" 
            ref = { ref => {
              this[key.id] = ref
              console.log(ref)}}
            id={key.keyTrigger}
            key={index}
            src={key.url}>
          </audio>
          {key.keyTrigger}
        </button>
        
        </div>
     
    })

    return (
      <div id="drum-machine">
        <div className="machine">
          <h1 className="header">DrumMachine 2000</h1>
        <div className="buttonArea">
        {padButton}
        </div>
        <div  id="display">
          <div className="displaybox" >
            {this.state.display}
          </div>
        </div>
        </div>
    
 
      </div>
    );
  }
}


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


Yes, but I would rename your parameter, because what is passed is not the event object (like in the displayHandler method).

playSound(refID) {
  this[refID].play();                  //<-----here
  this[refID].currentTime = 0          //<-----here
}

Also, I would still simplify the ref prop to be:

ref={ ref => this[key.id] = ref }

That makes sense and it is cleaner.

Thank you very much for helping on this!!! Now I get to move forward to keypress part!