Milo K
Milo K

Reputation: 65

Pass data from child to parent

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

Answers (2)

Milo K
Milo K

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

mfakhrusy
mfakhrusy

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

Related Questions