useEventListener()

Use EventListener with simplicity by React Hook.

Supports Window, Element and Document and custom events with almost the same parameters as the native addEventListener options. See examples below.

The Hook

1import { RefObject, useEffect, useRef } from 'react'
2
3// See: https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect
4import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'
5
6// Window Event based useEventListener interface
7function useEventListener<K extends keyof WindowEventMap>(
8 eventName: K,
9 handler: (event: WindowEventMap[K]) => void,
10 element?: undefined,
11 options?: boolean | AddEventListenerOptions,
12): void
13
14// Element Event based useEventListener interface
15function useEventListener<
16 K extends keyof HTMLElementEventMap,
17 T extends HTMLElement = HTMLDivElement,
18>(
19 eventName: K,
20 handler: (event: HTMLElementEventMap[K]) => void,
21 element: RefObject<T>,
22 options?: boolean | AddEventListenerOptions,
23): void
24
25// Document Event based useEventListener interface
26function useEventListener<K extends keyof DocumentEventMap>(
27 eventName: K,
28 handler: (event: DocumentEventMap[K]) => void,
29 element: RefObject<Document>,
30 options?: boolean | AddEventListenerOptions,
31): void
32
33function useEventListener<
34 KW extends keyof WindowEventMap,
35 KH extends keyof HTMLElementEventMap,
36 T extends HTMLElement | void = void,
37>(
38 eventName: KW | KH,
39 handler: (
40 event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event,
41 ) => void,
42 element?: RefObject<T>,
43 options?: boolean | AddEventListenerOptions,
44) {
45 // Create a ref that stores handler
46 const savedHandler = useRef(handler)
47
48 useIsomorphicLayoutEffect(() => {
49 savedHandler.current = handler
50 }, [handler])
51
52 useEffect(() => {
53 // Define the listening target
54 const targetElement: T | Window = element?.current || window
55 if (!(targetElement && targetElement.addEventListener)) {
56 return
57 }
58
59 // Create event listener that calls handler function stored in ref
60 const eventListener: typeof handler = event => savedHandler.current(event)
61
62 targetElement.addEventListener(eventName, eventListener, options)
63
64 // Remove event listener on cleanup
65 return () => {
66 targetElement.removeEventListener(eventName, eventListener)
67 }
68 }, [eventName, element, options])
69}
70
71export default useEventListener

Usage

1import React, { useRef } from 'react'
2
3import { useEventListener } from 'usehooks-ts'
4
5export default function Component() {
6 // Define button ref
7 const buttonRef = useRef<HTMLButtonElement>(null)
8 const documentRef = useRef<Document>(document)
9
10 const onScroll = (event: Event) => {
11 console.log('window scrolled!', event)
12 }
13
14 const onClick = (event: Event) => {
15 console.log('button clicked!', event)
16 }
17
18 const onVisibilityChange = (event: Event) => {
19 console.log('doc visibility changed!', {
20 isVisible: !document.hidden,
21 event,
22 })
23 }
24
25 // example with window based event
26 useEventListener('scroll', onScroll)
27
28 // example with document based event
29 useEventListener('visibilitychange', onVisibilityChange, documentRef)
30
31 // example with element based event
32 useEventListener('click', onClick, buttonRef)
33
34 return (
35 <div style={{ minHeight: '200vh' }}>
36 <button ref={buttonRef}>Click me</button>
37 </div>
38 )
39}

Edit on CodeSandbox

See a way to make this page better?
Edit there »