Reputation: 65
I'm starting with React and spent hours on this problem. I've managed with playing sound (without keyboard yet, but it's problem for later) but i can't get a sound name(padId from Drumpad component) to display in #display(in DrumMachine component).
I could do it within one component but i know that it's important to divide code on smaller parts. So I would like to do it this way (or maybe i should make it even smaller?). I tried to pass it in props but i'm doing something wrong. In comments rests of my last attempt
import React from 'react';
import './DrumMachine.scss';
const Pads = [
[
{padId: "ching_gamelan", padKey: "Q", padUrl: "/sounds/ching_gamelan.mp3"},
{padId: "ching_gamelan2", padKey: "W", padUrl: "/sounds/ching_gamelan2.mp3"},
{padId: "hit_stick", padKey: "E", padUrl: "/sounds/hit_stick.mp3"}
],
[
{padId: "karimba", padKey: "A", padUrl: "/sounds/karimba.mp3"},
{padId: "pan_pipe", padKey: "S", padUrl: "/sounds/pan_pipe.mp3"},
{padId: "synthesiser", padKey: "D", padUrl: "/sounds/synthesiser.mp3"}
],
[
{padId: "tifu", padKey: "Z", padUrl: "/sounds/tifu.mp3"},
{padId: "tifutifu", padKey: "X", padUrl: "/sounds/tifutifu.mp3"},
{padId: "ukulele", padKey: "C", padUrl: "/sounds/ukulele.mp3"}
]
];
class Drumpad extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
playSound() {
const sound = document.getElementById(this.props.padKey);
sound.currentTime = 0;
sound.play();
}
activePad() {
const active = document.getElementById(this.props.padId);
active.className = "drum-pad active";
setTimeout(() => (active.className = "drum-pad"), 100);
// this.props.getSoundName(this.props.padId); - not working
}
handleClick(event) {
this.playSound();
this.activePad();
};
render() {
return (
<div className="drum-pad" id={this.props.padId} onClick={this.handleClick}>
<audio className="clip" id={this.props.padKey}>
<source src={this.props.padUrl} type="audio/mp3" />
</audio>
<span>{this.props.padKey}</span>
</div>
);
}
}
class DrumMachine extends React.Component {
constructor(props) {
super(props);
this.state = {
currentSoundName: '',
currentSoundUrl: ''
};
this.getSoundName = this.getSoundName.bind(this);
}
getSoundName(name) {
this.setState({
currentSoundName: name
});
} // this.props.getSoundName(this.props.padId); - not working
render() {
const DrumGroups = Pads.map(function(a) {
return (
<div className="drum-group">
{a.map(i => <Drumpad padId={i.padId} padKey={i.padKey} padUrl={i.padUrl} /*getSound={this.props.getSoundName} - not working*/ />)}
</div>
);
});
const Zapsplat = (
<span className="zapsplat">Sound effects obtained from https://www.zapsplat.com</span>
);
return (
<div className="container">
{Zapsplat}
<div id="drum-machine">
<span id="display">{this.state.currentSoundName}</span>
<span id="drumpads">{DrumGroups}</span>
</div>
</div>
);
}
}
export default DrumMachine;
To sum up. I want to get the padId after clicking a pad and pass it into DrumMachine's state "currentSoundName".
Thank you in advance
Upvotes: 0
Views: 60
Reputation: 65
Ehh, I was so close and so far at once. Thank you @mfakhrusy for your help.
There was also one more thing missing, but thanks to this topic on stackoverflow i found this and now it works perfectly
const DrumGroups = Pads.map((a) => {
return (
<div className="drum-group">
{a.map(i => <Drumpad padId={i.padId} padKey={i.padKey} padUrl={i.padUrl} keyCode={i.keyCode} getSound={this.getSoundName} />)}
</div>
);
});
Edit: According to @mfakhrusy advice, used arrow function.
Upvotes: 1
Reputation: 1198
<div className="drum-group">
{a.map(i => <Drumpad padId={i.padId} padKey={i.padKey} padUrl={i.padUrl} getSound={this.getSoundName} />)}
</div>
edited, just pass the method to getSound
props, and access it on the activePad
method on Drumpad component:
your activePad should be like this,
activePad() {
const active = document.getElementById(this.props.padId);
active.className = "drum-pad active";
setTimeout(() => (active.className = "drum-pad"), 100);
this.props.getSound(this.props.padId);
}
Upvotes: 0