Tell us what’s happening:
the app working fine on click I can here the sounds. Also, if I click the keyboard its working. Unfortunately, it’s not passing tests. I wish someone could help me.
Your code so far
here is the code so far fro every pad:
for the keypress i’m using a custom hook useKeyPress :
function useKeyPress(targetKey) {
// State for keeping track of whether key is pressed
const [keyPressed, setKeyPressed] = useState(false);
// If pressed key is our target key then set to true
function downHandler({ key }) {
if (key === targetKey) {
setKeyPressed(true);
}
}
// If released key is our target key then set to false
const upHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(false);
}
};
// Add event listeners
useEffect(() => {
window.addEventListener("keydown", downHandler);
window.addEventListener("keyup", upHandler);
// Remove event listeners on cleanup
return () => {
window.removeEventListener("keydown", downHandler);
window.removeEventListener("keyup", upHandler);
};
}, []); // Empty array ensures that effect is only run on mount and unmount
return keyPressed;
}
You have two handlers for keydown and keyup, which fire quite fast when the tests “click” on a drumpad. I’d remove the keyup handler altogether. The fact that you almost instantly set the state from keyPressed back to false could mess things up. Instead, I’d set a timeout of maybe 300ms after a keydown event.
In your playAudio function, you create a new audio element each time, but the audio that should be playing is the one with the id="Q" etc inside your African/Bassbell… components
You’re not displaying the name of the current clip in the display, it just says “display”
If you remove the keyup, you need something else to set the state of keyPressed back to false (that’s why I recommended using a setTimeout with 300 milliseconds). Because if you don’t set it back to false, its state will always be true after the first keypress, and if its state doesn’t change, it won’t re-render and play the audio again.
I’ve looked at the tests, and they trigger all three possible events (keyDown, keyPress and keyUp) at the same time, so having more than one listener for key events is likely going to cause trouble with the tests.
I could think of two options here. The easier one (if you’re more familiar with Vanilla JS DOM manipulation) is to use querySelector in your play function to grab the audio element. Instead of passing in the src, you pass in the id of the audio element.
Direct DOM manipulation like that, however, is kind of frowned up in a React App. It won’t make the tests break, but if you want to do it the React way, you’d need the useRef hook. It lets you create a reference to each audio element, so you can access it directly without Vanilla’s querySelector.
Thanks a lot for your time and explantion. I’m new to react, and programming in general, so I know I’m doing some stupid stuff, but that’s how we learn.
First of all, nobody would kill you if you just took the easy route and make use of document.querySelector(audioId)
to grab the <audio> tag and play it.
As for useRef - in the version you posted above, you’re using it in your parent component Pad, which renders nine DrumPads, but all with the same audioRef. That cannot work, the child components themselves need to use useRef to get a reference to their audio elements. To use that reference, you have to access the .current property on it.
BTW I just noticed that the timeout of 300ms that I suggested is far too long, I revisited my own version of this project and a timeout of 10ms made my tests pass (while 300 made them fail). Don’t know if that helps, just wanted to mention it.
I’ll try with 10ms timeout. I’m thinking to redo all the project from scratch and to put all audio in one list of object with their id, url and all. Because I’ve just saw the example in code pen what they give us. I think it’s much easier but I didn’t think of it before. I’m thinking to use the map method to output the different pads.
This is a perfect use case for .map, and you’ll often see it in React. All the pads are essentially the same component, with the only difference being their ids/keyCodes/audio sources. React really shines when you have repetitive code blocks like that.
I just checked and even the example project uses document.getElementById to grab the audio element. I wouldn’t call it good practice, but this is a project for beginners and I guess they didn’t want to overcomplicate things with less-common hooks like useRef.
Yeah I’ve built now the template with .map it’s really useful. Ig they didn’t use the useRef hook bcz the course uses the “old react”, which use the class components and not the modern react with functional components. However I prefer the “modern react” as I found it more flexible and easier to understand. I can’t thank you enough for your help and the time you gave me.