I'm not satisfied with the responses to this kind of question so here's my take / solution. Keep in mind this uses React but can also be done natively.
(1) Add event listeners
const [userInteracted, setUserInteracted] = useState(false)
useEffect(() => {
const handleInteraction = (event) => { setUserInteracted(true); console.log(`Event log for: ${event}`); }
document.addEventListener('click', handleInteraction, true)
document.addEventListener('scroll', handleInteraction, true)
return () => {
document.removeEventListener('click', handleInteraction('click'))
document.removeEventListener('scroll', handleInteraction('scroll'))
}
}, [])
(2) Use native browser detection object
if (navigator.userActivation.hasBeenActive) { doSomething() }
I personally use this on a div which plays audio when hovered over:
const App = () => {
const [userInteracted, setUserInteracted] = useState(false)
const audioRef = useRef(new Audio(BirdSinging))
const playAudio = () => { if (audioRef.current && userInteracted && navigator.userActivation.hasBeenActive) audioRef.current.play() }
const stopAudio = () => {
if (audioRef.current && userInteracted) {
audioRef.current.pause()
audioRef.current.currentTime = 0
}
}
// avoids play() failed because the user didn't interact with the document first
useEffect(() => {
const handleInteraction = (thing) => { setUserInteracted(true); console.log(thing); }
document.addEventListener('click', handleInteraction, true)
document.addEventListener('scroll', handleInteraction, true)
return () => {
document.removeEventListener('click', handleInteraction('clik'))
document.removeEventListener('scroll', handleInteraction('scr'))
}
}, [])
useEffect(() => {
return () => {
audioRef.current.pause()
}
}, [])
return (
<div className="logo" onMouseEnter={playAudio} onMouseLeave={stopAudio}>
<img src={Logo} alt="Logo" />
</div>
)
}