<div id="root"></div>
@import url('https://fonts.googleapis.com/css2?family=Black+Ops+One&display=swap');

* {
  color: black;
}



.box {
  display:grid;
  grid-template-columns: auto auto auto;
  grid-template-rows: auto auto auto;
  width: 10vw;
  height: 10vw;
  grid-column-gap: 0.2vw;
  grid-row-gap: .2vw;
  
}

.padbtn {
  border: .2px solid black
}

#display {
  height:25px;
  font-family: 'Black Ops One';
}
// array of objects containing sound clips, key codes and rest of data needed
const bNames = [
      {
    keyCode: 81,
    keyTrigger: 'Q',
    id: 'Heater 1',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3'
  },
  {
    keyCode: 87,
    keyTrigger: 'W',
    id: 'Heater 2',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3'
  },
  {
    keyCode: 69,
    keyTrigger: 'E',
    id: 'Heater 3',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3'
  },
  {
    keyCode: 65,
    keyTrigger: 'A',
    id: 'Heater 4',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3'
  },
  {
    keyCode: 83,
    keyTrigger: 'S',
    id: 'Clap',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3'
  },
  {
    keyCode: 68,
    keyTrigger: 'D',
    id: 'Open HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3'
  },
  {
    keyCode: 90,
    keyTrigger: 'Z',
    id: "Kick n' Hat",
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3'
  },
  {
    keyCode: 88,
    keyTrigger: 'X',
    id: 'Kick',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3'
  },
  {
    keyCode: 67,
    keyTrigger: 'C',
    id: 'Closed HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3'
  }
  ]


//button componenet for individual button
const Button = (props) =>{
  
  //function that plays sound on specific button
  let playSound=(e)=>{
    const audio = document.querySelector(`#${props.keyTrigger}`);
    audio.play();
    props.soundSetter(props.id)
  }
  // event listener for key presses
  const keyHandle = (event) => {
    if (event.keyCode === props.code) {
    const audio = document.querySelector(`#${props.keyTrigger}`);
    audio.play();
    props.soundSetter(props.id)
    }
  }

  // useEffect hook that trigers functions after componenet renders
  React.useEffect(() => {
    document.addEventListener("keydown", keyHandle);
    return () => {
      document.removeEventListener("keydown", keyHandle)
    }
  }, []);
 
  return(
    <button className="padbtn" onClick={playSound}> 
      <p>{props.children}</p>
      <audio id={props.keyTrigger} src={props.url} className="clip"></audio>
    </button>

  )
  
}


//app that holds all 9 buttons
const App = () => {
  let [sound, setSound] = React.useState('None') //sound that currently played is stored in this state

  
  //map function that creates array of buttons presented in the view, takse button componenet and renders it into 9 individual button componenets
  const listItems = bNames.map(({keyCode, keyTrigger, id, url}, i) =>
      <Button soundSetter={setSound} sound={sound} url={url} key={i} id={id} code={keyCode} keyTrigger={keyTrigger} >
       {keyTrigger}
      </Button>
  );
                               
  return(
    <div id="pad">
        <div id='display'>
        {sound}  
        </div>
        <div className="box"> 
        {listItems}
        </div>                           
    </div>
  )
}
ReactDOM.render(<App/>, document.querySelector("#root"));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/material-ui/4.11.3/index.js
  4. https://cdn.jsdelivr.net/npm/uifx@2.0.7/build/index.min.js