Greetings!
I am working on the React drumpad project, and I’m having a bit of trouble with my drumpad buttons. I am using the Array.map method to map over an array of objects to make the buttons, and it works rather nicely for their appearance but for some reason it only assigns the audio link of the last button to all of them after rendering. Here’s the code:
const buttons = [{letter: "Q", url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3"}, {letter: "W", url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3"}, {letter: "E", url:"https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3"}, {letter: "A", url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3"}, {letter: "S", url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3"}, {letter: "D", url: "https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3"}, {letter: "Z", url: "https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3"}, {letter: "X", url: "https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3"}, {letter: "C", url: "https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3"}];
function Buttons(){
const audioRef = useRef();
//currently only plays the audio from the last url for all buttons.
const handleAudio = () => {
audioRef.current.play();
}
return(
<div id="button-container">
{buttons.map((btn) => <button onClick={handleAudio} className="drum-pad" id={btn.letter}>{btn.letter}<audio ref={audioRef} src={btn.url} /></button>)}
</div>
)
}
How do I assign each button the corresponding link in its object in the array? It’s working for the letters.
Thank you so much!!
(by the way, do you know if there’s a way to make automatic line breaks in my code above so it doesn’t look annoying for people on this forum?)
You only have one ref you would need an array (or object I guess).
I have seen this question a number of times and seen a number of different solutions. I’m honestly not sure what the most idiomatic way is.
function Buttons() {
// use an array
const audioRef = useRef([]);
// use the index
const handleAudio = (index) => {
audioRef.current[index].play();
};
return (
<div id="button-container">
{/* pass the index to handleAudio */}
{/* push the audio elements to the array */}
{buttons.map((btn, index) => (
<button key={btn.letter} onClick={() => handleAudio(index)} className="drum-pad" id={btn.letter}>
{btn.letter}
<audio ref={(ele) => audioRef.current.push(ele)} src={btn.url} />
</button>
))}
</div>
);
}
Edit: Remember to also add the key property to the buttons.
A lot of people just use native DOM methods to get to the elements as well. As long as you are not messing with the DOM (i.e. changing it) using native methods to get to elements should work just fine.
I want to return to this because I have almost finished my project and learned more about how React works. The above solution does work in principle visually, but because it pushes the refs onto an array on each render, I figured out the ref arrays were getting progressively larger very quickly and that led to problems. So instead of