Playing sound with React

Hi all.
I’ve been trying to get my code to play a sound in React.

Off course I tried with the <audio src="link to file" etc> element in my React render method first, but that didn’t work.

I have this now:
[https://codepen.io/cynthiab72/pen/BazyvLg?editors=0111]

from what I read here on the forums , others were having trouble with adding sound files to React, and to try using Refs.
I’m reading the Refs documentation , but it’s not working for me clearly.

You have to link to an actual sound file (.mp3, .wav), not a download. You can use the files/links from the example project.

Edit: Your code is also not correct, but it is a lot easier to test if you actually have a file that will playback for starters.

OK, thanks that helps for a start, a correct sound file :slight_smile:

You also don’t really need a ref to get the audio element by id, you might for example, use the text content of the button for the selector.

1 Like

I would also not use a state variable that you set right before the DOM selector (setState is asynchronous). Just get the value from the element and use it for the DOM selector.

Just as an example:

playSound(event){
  // button text
  const id = event.target.innerText;
  // get the audio element with the same id as the button text
  document.getElementById(id).play();
}
1 Like

Oke thanks, innerText makes a lot of sense and much simpler :slight_smile:

I found this tutorial :

Which helped me figure it out finally

It’s working correctly from what I can tell, but off course only 3 tests are passing . I’m hoping I’m not too far of ,with what I have so far ?

I’m a bit unsure what they mean with “a unique id that describes the audio clip” for story 3. Does what I have look correct at least ? I guess just because it seems to work correct it can still be wrong?

I’m taking forever with this one :frowning:
Thanks:)

It just means each element with the drum-pad class should also have an id attribute.

I know it says “id that describes the audio clip” but the test can’t actually check that it “describes” anything. I’m guessing it is just referring to the name of the audio clip for the id value.

Thanks. So you think that’s the only thing I need to change?
I was worried about having to change a lot and stressed about it.
Should check that each test passes before I continue from now on :slightly_smiling_face:

Yes, for user story 3. Each of the buttons elements just needs a (unique) id.

Hmm I added the id for user story 3 and it’s still not correct apparently.
I can see that in getSound() the id is not updated correctly.
I already had a callback function (playsound) added to deal with async setstate, but it’s still not correct with updating the id.
I read that here:

even trying async/await:

still not :frowning:
Tests 4, 5, and 6 are still failing. I’m at a complete loss.
Could it be because I’m returning a component in render to render the audio element ?

When I press the drum buttons the correct id is returned, but when I run the tests , just the id “c” is returned every time ?

I’m just hoping for some insight/clues.

Thanks ! :slight_smile:

I might be able to solve this without further help. It might need a map function returning button and audio elements etc in render. Hopefully this will work. At least my experimental code is rendering.

here’s my last update:

But it’s still failing tests 5 and 6.
I feel like i’m getting nowhere, yet it seems to play the correct sounds when I press each button? It’s very hard to fix something if you don’t know what needs to be fixed

Please just share a hint only, I want to try to solve this myself :slight_smile:

Oke I managed to solve it for test 5, just test 6 left :slight_smile:

You need to listen for the keyboard event and handle the logic for playing the correct sound. Right now you are only listening for the click event.


BTW, I don’t think the async/await is doing what you think it is. I know it “works”, but the reason why it works may not be what you believe it to be.

You have not implemented any error handling to deal with the fact that you are listening for click events on the document but your handler does not check that the event.target is valid, i.e. that it is fired on an element with the properties you are expecting it to have for the logic inside it to work.

Your getSound handler is in fact throwing whenever you click something that is not a button. If you wrap your code in a try/catch you can see this. The reason why you do not see an error is just the nature of how an async function works (to the best of my knowledge, the async function will not throw but will return a rejected Promise). So when it “throws” it never runs the await this.setState() and you do not see the error that would otherwise have happened.

Here is the handler with a try/catch and a log to show when setState actually runs. Click something other than the buttons, then click one of the buttons, look at the console.

async getSound(event) {
  try {
    if (this.state.power) {
      const id = event.target.innerText;

      const newarr = [];
      const switchmap = this.state.switch
        ? this.state.soundsB
        : this.state.soundsA;
      const arr = switchmap.map(function (item) {
        if (item.id === id) {
          newarr.push(item);
        }
      });
      await this.setState(
        {
          text: newarr[0]["text"],
          src: newarr[0]["src"],
          id: newarr[0]["id"]
        },
        () => {
		  console.log("this code ran");
          this.playSound();
        }
      );
    }
  } catch (err) {
    console.log("getSound is throwing");
  }
}

Thanks for the reply but I just feel defeated now. Basically I have to start all over? I feel it’s all wrong now and what makes it worse it that is seems to work .

1 Like

No, you don’t have to start all over. If you deal with the keyboard events and you pass all the tests then you have in fact passed all requirements.

Should you keep the async/await like it is now? Probably not, but you can. Would fixing the actual issue be hard? Not really, you just need to make sure you have valid data for the setState

Here is some example hint code you can put in your handler function, see if you can figure out how to use it for error handling (if the target is not a button return out of the function).

console.log(event.target.classList.contains('drum-pad'))


Edit: I would also like to point out that you have learned something valuable and this “issue” is actually interesting if you think about it. I know it can be hard to think like this when you are in the fray of things but I’m just pointing out the “cup is half full” side of things.

Learning is taking place, that is all that really matters.

1 Like

Thanks for the reply. Off course this is not the first time I’ve felt like this. The has caused me many frustrations, anger & tears. I’ll try to pick up the pieces but it’s a struggle right now.

So does it test the code by keyboard keypresses only , that’s the impression I’m getting ? Thanks

You learn way more struggling than you do cruising. I know it can be frustrating, but trust me as backward as this might sound, getting stuck moves you forward. Right now you are just focused on the end goal of getting this to work/pass, but that is not actually the point of the challenge. The point is to learn and that can only come through some struggle. If you did not struggle it would mean you were doing something you already knew how to do, which will only help maintain knowledge not move it forward.

Do you mean for the keyboard test or what?

Specifically, the test triggers a keydown, keypress, keyup event on the button elements, and looks at the audio element paused property to see if it is playing or not.

1 Like