Please help! - React - Drum Machine - Play sound with click event

I am just starting to build a drum machine: https://learn.freecodecamp.org/front-end-libraries/front-end-libraries-projects/build-a-drum-machine
I am in the very first steps.
There is a display to show text, for now, the address of the file that should sound.
Then there are nine drum-pads. You can click on them.
Also you can press the correspondig keys on the keyboard.

With the keys I can play the sounds, but no by clicking.

I want to know:

  • How to play the current sound (it is on the state of the app) by clicking on any of the drum-pads?

The page where you can play the sounds https://s.codepen.io/zdflower/debug/zaZRrJ/RBrOJNPyZgGM
The code to read is here: https://codepen.io/zdflower/pen/zaZRrJ?editors=0010

I have had a little look at your code. There are a few things that you might want to look at:

  1. You are calling the playSound function from the render function- You want to sound to be playing when the user clicks or presses a key, not when the display updates. It is a subtle difference, but you current setup gives an error when the component mounts.
  2. As you have sounds working for key presses and not when the user click, this points to an error in your handleClickPlay function. You need to change the currentSound in setState to source not text. If you look at the console, you will see that there is an error coming back from the server because your link has “sounds.” at the end.
  3. If you look at your handleKeyPress function, you could simplify it:
let currentSound = soundFilesNamesAndKeys[event.key];

You would need to handle transforming the text to lowercase and what to do if there is no value in the object as it will come back undefined, but it might help keep your code DRY.

Hope this is of some use and points you in the right direction :slight_smile:

1 Like

Thank you so much! :grinning:

As you have sounds working for key presses and not when the user click, this points to an error in your handleClickPlay function. You need to change the currentSound in setState to source not text. If you look at the console, you will see that there is an error coming back from the server because your link has “sounds.” at the end.

After changing that, the click triggers the sound ok.

I will check the other points.

Thanks again!

I’ve been making some changes, thanks to your suggestions.

It was a great idea to simplify the handleKeyPress function. Also, although it still calls the playsound from render, there is a conditional test, so it only tries to reproduce the sound if there is a filename to play assinged to the respective property in the state.

It doesn’t pass one test:

  1. When I press the trigger key associated with each .drum-pad, the audio clip contained in its child

If you have a moment (whenever it could be), would you tell me what you think, please?

Here is a previous version that works and passes the tests

I’m glad you found the solutions helpful :smile:.

I think the source of the problem is that the test suite creates an event to simulate a keypress, whereas a keydown event is trigger when you press a key. Not quite sure how it is all working to be honest and why you original project works but this doesn’t, but the example project uses a keyCode (eg. W is 81) instead of a letter. If you put console.log(event) at the top of the handleKeyPress function and compare the result from pressing a key to running the tests, you will see the difference.

In terms of the rest of your code, I think it’s quite nice. If it were my code then I might make the following changes:

  1. Your “Another idea code” is, I think, much better than the current code as it is easier to read and it only evaluates isValidKey once.

  2. Your sound display text could be more user friendly:
    “https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3” or “Heater-1”
    (Imagine someone with no web experience using your website)

  3. Something I learnt from the React docs (sorry I can’t remember which part) was to keep things stored in state to a minimum. You only have one thing that is changing which is the sound, so all you need to have in the state is some kind of reference to the sound. If you know what sound is the current one, you can then work out what the link or text should be. There are several ways this can be achieved, but as an example using you current display text as a model, if you state contains the link then:

this.setState({currentSound: link});// easy to manage state 

render() {
  let text = this.state.currentSound + " sounds." // only one place to manage display text
  return <p>{text}</p>
}
  1. I can’t see anything you playSound function is returning to render, so assuming you want to keep the playSound call in your render function, you could do something like this:
render() {
  if (soundNeedsToBePlayed) {
    playSound();
  }
  return (
    // stuff to display
  )
}

Hope this helps and that I haven’t waffled on too much :slight_smile:

1 Like

Excellent! I will work with this and then I tell you the results. Can’t say enough “thanks” to you! :grinning:

You were very helpful! :clap: Thanks to your observations I could make progress.
Apparently the test uses a keyboard event which has an undefined key property. So, I used keyCodes, although it is a deprecated property.

Here: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode says that keyCode is deprecated and to avoid using it. And here: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent it is recommended to use key instead.

Glad to be of help :smile:.