Drum Machine: tests 5 & 6 not passing

Heyho,

I built a basically styled functional version of the drum machine as required. I’m using modern react (functional components and hooks).
As far I can see, the app does what it should do. But tests 5 & 6 don’t pass. I know i could simply build another version without react and using plain js eventlisteners. But actually I like my solution and I would really want to know what’s the matter here. So I would be very glad if anybody could help me!? Tank you! :slight_smile:

Here’s the App-Component:

import React, { useState, useEffect, useRef } from 'react'

import drumData from "./drumData"
import DrumPad from "./DrumPad"


function App() {
  const [drumPattern, setDrumPattern] = useState([])
  const keyDown = useRef(null)

  function handleKeyDown(event) {
    drumData.forEach(drum => {
      drum.id === event.key.toUpperCase() ? handleDrum(drum.description) : {}
    })
  }

  function handleDrum(desc) {
    const matchingDrum = drumData.find(drum => drum.description === desc)
    setDrumPattern(prevDrumPattern => [...prevDrumPattern, matchingDrum])
    let audio = new Audio(matchingDrum.url)
    audio.play()
  }

  const drumPads = drumData.map(drum => {
    return (
    <DrumPad 
      key={drum.id} 
      drum={drum} 
      drumPattern={drumPattern} 
      handleDrum={handleDrum} />
    )
  })

  return (
    <div id="App-Wrapper" className="" tabIndex={0} ref={keyDown} onKeyDown={(event) => handleKeyDown(event)}>
      <div id="drum-machine" className="">
        <div id="drumpad-grid">
          {drumPads}
        </div>
        <div id="setting-grid">
          <div id="display">
           {drumPattern.length > 0
            ? drumPattern[drumPattern.length - 1].description 
            : " "}
          </div>
        </div>
      </div>
    </div>
  )
}

export default App

And here the DrumPad-Component:

import React, { useEffect, useRef } from 'react'


function Drumpad(props) {
    const {drum, drumPattern, handleDrum} = props
    // const audioElt = useRef()

    // useEffect(() => {
    //     playSound()
    // }, [drumPattern])

    // function playSound() {
    //     const latestDrum = drumPattern[drumPattern.length - 1]
    //     if (latestDrum && 
    //         drum.description === latestDrum.description) {
    //         audioElt.current.play()
    //         }
    // }

    return (
        <button 
            id="description" 
            className="drum-pad"
            onClick={() => handleDrum(drum.description)} >
            <audio 
                id={drum.id === "Y" ? "Z" : drum.id}
                src={drum.url} 
                className="clip"
                // ref={audioElt}
                >
            </audio>
            {drum.id === "Y" ? "Z" : drum.id}
        </button>
    )
}

export default Drumpad

Oh I forgot the useEffect in the App-Component (for initial focus on the app to get the keyDowns). But this didn’t cause the problem.

Here is it:

  useEffect(() => {
    keyDown.current.focus()
  }, [drumPattern])

Finally I got a solution that passes the tests:

import React, { useState, useEffect, useRef } from 'react'

import drumData from "./drumData"


function App() {
  const [drumPattern, setDrumPattern] = useState([])
  const keyDown = useRef(null)

  const key = useRef(null)

  useEffect(() => {
    keyDown.current.focus()
  }, [drumPattern])

  function handleKeyDown(event) {
    drumData.forEach(drum => {
      drum.id === event.key.toUpperCase() ? handleDrum(drum.description) : {}
    })
  }

  function handleDrum(desc) {
    setDrumPattern(prevDrumPattern => [...prevDrumPattern, desc])
    key.current.children.forEach((drumPad) => {
      if (drumPad.id === desc) {
        drumPad.firstChild.play()
      } 
    })
  }

  const drumPads = drumData.map(drum => {
    return (
      <button
        key={drum.id}
        id={drum.description}
        className="drum-pad"
        onClick={() => handleDrum(drum.description)} >
        <audio 
          id={drum.id}
          src={drum.url} 
          className="clip"
           >
        </audio>
        {drum.id}
      </button>
    )
  })

  return (
    <div id="App-Wrapper" className="" tabIndex={0} ref={keyDown} onKeyDown={(event) => handleKeyDown(event)}>
      <div id="drum-machine" className="">
        <div id="drumpad-grid" ref={key}>
          {drumPads}
        </div>
        <div id="setting-grid">
          <div id="display">
           {drumPattern.length > 0
            ? drumPattern[drumPattern.length - 1] 
            : " "}
          </div>
        </div>
      </div>
    </div>
  )
}

export default App

Trick was to get the whole drum-pad referenced instead of each drum.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.