Build a Drum Machine - Style on keydown

Tell us what’s happening:

I have completed the drum machine challenge, but I have an css transform+transition which occur when the pads are clicked and I would like this to also happen on the relevant keypress. There is a demo here.

Any help much appreciated.

Your code so far
The full code is available here, but the pertinent javascript is:

class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      playing: ''
    }
  }

  componentDidMount() {
    document.addEventListener('keydown', this.handleKeyDown)
  }

  playSound = sound => {
    this.setState(
      {
        playing: sound
      },
      () => {
        this[sound.toLowerCase()].currentTime = 0
        this[sound.toLowerCase()].play()
      }
    )
  }

  handleKeyDown = e => {
    e.preventDefault()
    const keySoundPair = samples.filter(
      element => element.key === e.key.toUpperCase()
    )
    if (keySoundPair.length > 0) {
      this.playSound(keySoundPair[0].sound)
    }
  }

  render() {
    return (
      <div className="App">
        <div className="pads">
          {samples.map(element => {
            return (
              <Pad
                key={element.key}
                ref={ref => {
                  this[element.sound.toLowerCase()] = ref
                }}
                sound={element.sound}
                letter={element.key}
                playSound={this.playSound}
              />
            )
          })}
        </div>
        <div id="display">{this.state.playing}</div>
      </div>
    )
  }
}

const Pad = React.forwardRef((props, ref) => (
  <div
    id={props.sound}
    className="drum-pad"
    onClick={() => props.playSound(props.sound)}
  >
    {props.letter}
    <audio
      ref={ref}
      src={`sounds/${props.sound.toLowerCase()}.wav`}
      className="clip"
      id={props.letter}
    />
  </div>
))

And the pertinent CSS is:

.drum-pad:active {
  transform: scale(1.1);
  transition: all 0.07 ease-in-out;
  box-shadow: 0 0 5px 3px #62727b;
}

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36.

Link to the challenge:

You could take this approach.

You can also create a regular css class called .active along with your pseudoclass :active. Then whenver a key is pressed, you can have something like an activeKey state toggle for a short period of time. Then while activeKey state is on your keys can listen to that and have that class be applied to them for a short time.

Hope this makes sense!

1 Like

This was my first thought too, and I have implemented this solution now. However…

To achieve this, I use code like this

  toggleActive = key => {
    this.setState(
      {
        active: key
      },
      () =>
        setTimeout(() => {
          this.setState({
            active: ''
          })
        }, 70)
    )
  }

Various sources online warn that React can bundle setState() calls. Doesn’t this mean that I can’t rely on the above approach?

Even though I call the setState() method 70ms apart, React might decide to hold off on executing the first one, batch it up with the second one and then call both immediately in succession. I’m not sure if I’m understanding correctly.

It does seem to work though.

Thanks.