Basically I’m working on a drum machine project and I need each out of 9 buttons that will be showed on the screen to be clickable with the mouse click as well as by a related keyboard key.
Setting it up to work with mouse with onClick
event attached to each button click was pretty straightforward, but I’m having difficulties with making it to work with the keyboard.
So far I have done the following:
- Set up
componentDidMount()
with an event listener to read each key press:
componentDidMount() {
const setKey = (event) => { this.setState({ keyPressed: event.key.toUpperCase() }) }
document.addEventListener('keydown', setKey);
}
- Set up
componentDidUpdate()
to check whether a currently pressed key is among keys that are used in the app, then it triggershandleClick
function and passes couple arguments:
componentDidUpdate() {
if (this.state.keyList.includes(this.state.keyPressed)) {
this.handleClick("keydown", this.state.keyPressed)
}
}
- Finally,
handleClick
checks whether it is a “keydown” or “click” event and plays the corresponding<audio>
:
handleClick(event) {
if (arguments[0] === "keydown") {
var audio = document.getElementById(arguments[1])
} else {
const { name, value } = event.target
this.setState({
displayValue: value
})
var audio = document.getElementById(name)
}
audio.paused ? audio.play() : audio.currentTime = 0
}
My code is currently able to play corresponding audio for both scenarios, but I’m not sure how to make it display a corresponding value from the button in case when it is triggered by a keyboard button since I can’t figure out how to pass event.target
as it is done for onClick
scenario.
Also, probably the main issue, is that eventually I would like to set up CSS and Bootstrap for this project and the button should be changing it’s color when it is played, as well as when it is triggered by the keyboard. What I have done right now is rather a workaround and when the time comes to set it up, it won’t be working this way.
Is there anyway I could trigger buttons when a corresponding keyboard keys are pressed and behave in a way as it would when I do it via onClick
?
** My ReactJS code so far **
class App extends React.Component {
constructor() {
super()
this.state = {
displayValue: "",
keyPressed: "",
keyList: ["Q", "W", "E", "A", "S", "D", "Z", "X", "C"]
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount() {
const setKey = (event) => { this.setState({ keyPressed: event.key.toUpperCase() }) }
document.addEventListener('keydown', setKey)
}
componentDidUpdate() {
if (this.state.keyList.includes(this.state.keyPressed)) {
this.handleClick("keydown", this.state.keyPressed)
}
}
handleClick(event) {
if (arguments[0] === "keydown") {
var audio = document.getElementById(arguments[1])
} else {
const { name, value } = event.target
this.setState({
displayValue: value
})
var audio = document.getElementById(name)
}
audio.paused ? audio.play() : audio.currentTime = 0
}
render() {
return (
<div id="drum-machine">
<div id="display">{this.state.displayValue}</div>
<div className="drum-pad" id="pad-q">
<button type="button" name={this.state.keyList[0]} value="Chord 1" onClick={this.handleClick}>Q</button>
<audio className="clip" id={this.state.keyList[0]} src="https://s3.amazonaws.com/freecodecamp/drums/Chord_1.mp3"/>
</div>
<div className="drum-pad" id="pad-w">
<button type="button" name={this.state.keyList[1]} value="Chord 2" onClick={this.handleClick}>W</button>
<audio className="clip" id={this.state.keyList[1]} src="https://s3.amazonaws.com/freecodecamp/drums/Chord_2.mp3"/>
</div>
<div className="drum-pad" id="pad-e">
<button type="button" name={this.state.keyList[2]} value="Chord 3" onClick={this.handleClick}>E</button>
<audio className="clip" id={this.state.keyList[2]} src="https://s3.amazonaws.com/freecodecamp/drums/Chord_3.mp3"/>
</div>
<div className="drum-pad" id="pad-a">
<button type="button" name={this.state.keyList[3]} value="Shaker" onClick={this.handleClick}>A</button>
<audio className="clip" id={this.state.keyList[3]} src="https://s3.amazonaws.com/freecodecamp/drums/Give_us_a_light.mp3"/>
</div>
<div className="drum-pad" id="pad-s">
<button type="button" name={this.state.keyList[4]} value="Open HH" onClick={this.handleClick}>S</button>
<audio className="clip" id={this.state.keyList[4]} src="https://s3.amazonaws.com/freecodecamp/drums/Dry_Ohh.mp3"/>
</div>
<div className="drum-pad" id="pad-d">
<button type="button" name={this.state.keyList[5]} value="Closed HH" onClick={this.handleClick}>D</button>
<audio className="clip" id={this.state.keyList[5]} src="https://s3.amazonaws.com/freecodecamp/drums/Bld_H1.mp3"/>
</div>
<div className="drum-pad" id="pad-z">
<button type="button" name={this.state.keyList[6]} value="Punchy Kick" onClick={this.handleClick}>Z</button>
<audio className="clip" id={this.state.keyList[6]} src="https://s3.amazonaws.com/freecodecamp/drums/punchy_kick_1.mp3"/>
</div>
<div className="drum-pad" id="pad-x">
<button type="button" name={this.state.keyList[7]} value="Side Stick" onClick={this.handleClick}>X</button>
<audio className="clip" id={this.state.keyList[7]} src="https://s3.amazonaws.com/freecodecamp/drums/side_stick_1.mp3"/>
</div>
<div className="drum-pad" id="pad-c">
<button type="button" name={this.state.keyList[8]} value="Snare" onClick={this.handleClick}>C</button>
<audio className="clip" id={this.state.keyList[8]} src="https://s3.amazonaws.com/freecodecamp/drums/Brk_Snr.mp3"/>
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("root"))
Your browser information:
User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
.
Challenge: Build a Drum Machine
Link to the challenge: