Ian Springer
Ian Springer

Reputation: 233

Loop over all instances of component, log each state

I'm building out a simple drum machine application using ReactJS and could use some help understanding how to loop through all instances of a component while outputting each instance's state.

The application UI shows 16 columns of buttons, each containing 4 unique drum rows. There is a "SixteenthNote.js" component which is essentially on column containing each "Drum.js" instance. In the "DrumMachine.js" module, I am outputting "SixteenthNote.js" 16 times to display one full measure of music. When you click on a drum button, that drum's value is pushed into the SixteenthNote' state array. This is all working as intended.

The last part of this is to create a "Play.js" component which, when clicked, will loop through all of the SixteenthNote instances and output each instance's state.

Here is the "DrumMachine.js" module

class DrumMachine extends Component {
  constructor(props) {
    super(props);
    this.buildKit = this.buildColumns.bind(this);
    this.buildLabels = this.buildLabels.bind(this);
    this.buildAudio = this.buildAudio.bind(this);
    this.state = {
      placeArray: Array(16).fill(),
      drumOptions: [
        {type: 'crash', file: crash, title: 'Crash'},
        {type: 'kick', file: kick, title: 'Kick'},
        {type: 'snare', file: snare, title: 'Snare'},
        {type: 'snare-2', file: snare2, title: 'Snare'}
      ]
    }
  }

  buildLabels() {
    const labelList = this.state.drumOptions.map((sound, index) => {
      return <SoundLabel title={sound.title} className="drum__label" key={index} />
    })

    return labelList;
  }

  buildColumns() {
    const buttonList = this.state.placeArray.map((object, index) =>  {
      return <SixteenthNote columnClassName="drum__column" key={index} drumOptions={this.state.drumOptions}/>
    });
    return buttonList;
  }

  buildAudio() {
    const audioList = this.state.drumOptions.map((audio, index) => {
      return <Audio source={audio.file} drum={audio.type} key={index}/>
    })

    return audioList;
  }

  render() {
    return (
      <div>
        <div className={this.props.className}>
          <div className="label-wrapper">
            {this.buildLabels()}
          </div>
          <div className="drum-wrapper">
            {this.buildColumns()}
          </div>
        </div>
        <div className="audio-wrapper">
          {this.buildAudio()}
        </div>
      </div>
    )
  }
}

Here is "SixteenthNote.js" module

class SixteenthNote extends Component {
  constructor(props) {
    super(props);
    this.buildColumn= this.buildColumn.bind(this);
    this.buildDrumOptions = this.buildDrumOptions.bind(this);
    this.updateActiveDrumsArray = this.updateActiveDrumsArray.bind(this);
    this.state = {
      activeDrums: []
    }
  }

  buildDrumOptions() {
    return this.props.drumOptions;
  }

  updateActiveDrumsArray(type) {
    let array = this.state.activeDrums;
    array.push(type);
    this.setState({activeDrums: array});
  }

  buildColumn() {
    const placeArray = this.buildDrumOptions().map((button, index) => {
      return <Drum buttonClassName="drum__button" audioClassName="drum__audio" type={button.type} file={button.file} key={index} onClick={() => this.updateActiveDrumsArray(button.type)}/>
    })

    return placeArray;
  }

  render() {
    return (
      <div className={this.props.columnClassName}>
        {this.buildColumn()}
      </div>
    )
  }
}

Here is the "Drum.js" module

class Drum extends Component {
  constructor(props) {
    super(props);
    this.clickFunction = this.clickFunction.bind(this);
    this.state = {
      clicked: false
    }
  }

  drumHit(e) {
    document.querySelector(`.audio[data-drum=${this.props.type}]`).play();
    this.setState({clicked:true});
  }

  clickFunction(e) {
    this.state.clicked === false ? this.drumHit(e) : this.setState({clicked:false})
  }

  render() {
    const drumType = this.props.type;
    const drumFile = this.props.file;
    const buttonClasses = `${this.props.buttonClassName} drum-clicked--${this.state.clicked}`
    return (
      <div onClick={this.props.onClick}>
        <button className={buttonClasses} data-type={drumType} onClick={this.clickFunction}></button>
      </div>
    )
  }
}

Upvotes: 0

Views: 39

Answers (1)

grenzbotin
grenzbotin

Reputation: 2565

You will need to contain the information about the activeDrums in your DrumMachine component. That means:

In your DrumMachine component you create the state activeDrums like you have in your SixteenthNote.js. You will need to put your updateActiveDrumsArray function to your drumMachine component as well.

Then you pass this function to your SixteenthNote component like:

<SixteenthNote columnClassName="drum__column" key={index} drumOptions={this.state.drumOptions} onDrumsClick={this.updateActiveDrumsArray} />

After doing so, you can access that function via props. So, in your SixteenthNote component it should look like:

<Drum buttonClassName="drum__button" audioClassName="drum__audio" type={button.type} file={button.file} key={index} onClick={() => this.props.onDrumsClick(button.type)}/>

(Don't forget to get rid of the unneccessary code.)

With this, you have your activeDrums state in DrumMachine containing all the active drums. This state you can then send to your play component and do the play action there.

Upvotes: 2

Related Questions