Confusion about the executing sequence in React and html general

  1. Program purpose:
    Just put an audio element inside a button element, and the play of the audio is controlled by the click of the button.

  2. The following codes work perfectly in html:

<button onClick="Q.play()">audio controlled by button
<audio id="Q">
  <source src="https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3">
</audio>
</button>
  1. But when I try to put the above code inside React, it says the id of audio is not defined yet in the button tag:
const Pad = () => {
	return (
    <button onClick={Q.play}>
audio controlled by button
		<audio id="Q" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3">
		</audio>
      </button>
	);
};
ReactDOM.render(
  <Pad />, document.getElementById('root')
);
  1. My thought:
    I know that in React I can get it work by using class component and document.getElementById() and all those, however I am just wondering why it is not working here.
    Why the same code works in normal html but not in React? Is it something to do with the sequence of how the codes are being executed? Or what else?

I’m not sure that the original vanilla js way is a good pattern. I think it’s typically a better idea to have a reference to the dom Audio Object HTML DOM Audio play() Method).

In React, using the Document object is an anti-pattern as you should avoid manipulating the dom directly. Check out the useRef hook for that!

Hi!

But is this code correct?

“Q” in “Q.play()” isn’t something that the browser would know what it is either. And it shouldnt have the () because that means “execute” and you want it to be able to be executed. Maybe you meant onClick="play" and that function was defined somewhere?

Or maybe onClick="()=>{document.getElementById("Q").play()}" but idk whether this would work (and yet isn’t a good idea).

Try this for example:

    <button onClick={()=>{document.getElementById("Q").play()}}>
		<audio id="Q" 
               src="https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3">
		</audio>
    </button>

I get your point that there should not be the () here, but weirdly this code works like this, that it just calls the play method of the audio with the id Q, not another play method I defined somewhere else.

Yeah, and this code using document.getElementById works in React. Thanks. But I’m still not get why the same code works in normal html does not work in React.

Rather than querying the DOM directly, the more “React” way to do that would be with a ref, I would think.

The second one isn’t HTML, it’s JavaScript (JSX is something that’s translated to JS, it’s just dressed up to look like HTML to make it clear what the intention is), and there is no variable called Q. So when it’s rendered as HTML, there’s an event listener added that tries to run undefined.play()

As stated, you need a ref to do what you’re trying to do, which allows you to bypass how React normally works and will give you access to the actual DOM that eventually gets rendered.

The first one works because what browsers do with id attributes in actual HTML is set them as global JS variables (hence why ids in HTML have to be unique – if you had two called Q on a page, the second one would overwrite the first one). So there is an audio DOM element assigned to the variable Q, and audio objects have the method play. (Edit: relying on this behaviour is not a good idea, I can’t remember the caveats off the top of my head, but it definitely doesn’t work in some situations)

1 Like

I have no idea what React is to be honest. Just searched for smth that made sense. But I will inspect it.

Oh, because "id"s are global variables you can just call onClick=“Q…”?

I didn’t know this was a thing. Please let me know if I am wrong. I was expecting Q to be defined in a standard way ?

Nice explanation.

Yeah, so JS was originally just a very very lightweight way to add a sprinkling of interactivity to HTML when it couldn’t be done any other way. So there are quite a few things which were designed to make it convenient in that context. It not as if you’d try to use JS to build entire apps or anything :upside_down_face:! Once JS started being used for much more complex things…turns out a lot of the “convenient” things ended up being weird annoyances, but anyway:

idattribute

Neat explanation. I didn’t know that is why you can just call the ids like that in the console. I thought it was a feature of the dev tool.

But it is not the other way around, variables that you define in the “upper level” of the JS script won’t overwrite those globals, I think?

So we only “selectById” to be nice to other devs correct? Cause we could just use those variables? (sorry for the many Qs, I will just test some by myself.)