Home > database >  Issue with display click and keydown event listener result
Issue with display click and keydown event listener result

Time:01-14

I have tried to set up an event listener which would listen to the user's click or keydown inputs to display the associated clip name.

const audioClips = [
    {
        keyCode: 81,
        keyTrigger: "Q",
        id: "Heater 1",
        src: "https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3"
    },
    {
        keyCode: 67,
        keyTrigger: 'C',
        id: 'Snare',
        link: 'https://s3.amazonaws.com/freecodecamp/drums/Brk_Snr.mp3'
    }
]

function App() {

    const [displayClipName, setDisplayClipName] = React.useState('Click a key!')  

    React.useEffect(() => {
        document.addEventListener('keydown', (e) => {
            const keyDownUpperCase = e.key.toUpperCase()
            changeDisplay(keyDownUpperCase)
        });
        return () => {
            document.removeEventListener('keydown', changeDisplay)
        }
    }, [])
    
    const handleCLick = (e) => {
        const targetId = e.target.id.slice(e.target.id.length -1, e.target.id.length);
        console.log('here')
        changeDisplay(targetId)
    }

    const changeDisplay = (keyDownUpperCase, targetId) => {
        console.log(keyDownUpperCase)
        console.log(targetId)

        if (keyDownUpperCase || targetId === 'Q') {
            setDisplayClipName('You played: '   audioClips[0].id)
        }
        else if (keyDownUpperCase || targetId === 'C') {
            setDisplayClipName('You played: '   audioClips[8].id)
        }
        else {
            setDisplayClipName('You missed it, try again!')
        }
    }

    return (
    <div id="drum-machine" className="text-white text-center">
        <div id="display" className="container-fluid bg-info rounded p-2">
            <h1>FCC - Drum Machine</h1>
            <div onClick={handleCLick} className="pad-container bg-warning rounded p-3 m-3">
                {audioClips.map((clip) => (
                <Pad 
                    key={clip.id}
                    clip={clip}           
                />
                ))}
            </div>
            <h2>{displayClipName}</h2>
        </div>
    </div>
    )
}

My app looks like this but apparently, I am missing something because the third console.log(targetID) returns an empty string, and the displayClipName does only listen the first keydown input.

Any insights on that's wrong is more than welcome!

CodePudding user response:

Try adding an id attribute to the div. The div with the onClick handler needs to have an id attribute, for example:

<div id="example-id" onClick={handleCLick} className="pad-container bg-warning rounded p-3 m-3">

e.target.id returns the value of the id attribute of the tag the event was triggered against.

CodePudding user response:

When you add your eventListener you only provide the the key which is pressed. You also provide an anonymous function which can't be used to remove the event in the useEffect cleanup.

React.useEffect(() => {
  document.addEventListener("keydown", (e) => {
    const keyDownUpperCase = e.key.toUpperCase();
    changeDisplay(keyDownUpperCase);
  });
  return () => {
    document.removeEventListener("keydown", changeDisplay);
  };
}, []);

To fix the issue of the eventlisteners we can just use the changeDisplay function as a handler.

React.useEffect(() => {
  document.addEventListener("keydown", changeDisplay);
  return () => {
    document.removeEventListener("keydown", changeDisplay);
  };
}, []);

Then in the changeDisplay function we need some adjustments. Your changeDisplay takes in 2 arguments. One for an event and another for some id. We can just transform the key to upper case in the function no need to do it somewhere else. The rest of the functionality can stay the same.

const changeDisplay = (e, targetId) => {
  const keyDownUpperCase = e?.key?.toUpperCase();
  ...
};

Then there is the handleClick function. Which takes in a event, there is no need for that since we can simply provide the keyTrigger when we call the function. It can even we removed if you want to.

const handleClick = (id) => {
  changeDisplay(id);
};

For this example I just added a div around the Pad component, if its a custom component you can add a onClick to the component instead of the extra div. We change the onClick to call handleClick with the first parameter of null since we don't have a KeyboardEvent and the second parameter the clip.keyTrigger for the changeDisplay to handle.

<div className="pad-container bg-warning rounded p-3 m-3">
  {audioClips.map((clip) => (
    <div onClick={() => handleClick(null, clip.keyTrigger)}>
      <Pad key={clip.id} clip={clip} />
    </div>
  ))}
</div>
  • Related