Appearance
useEventListener
Use EventListener with ease. Register using addEventListener on mounted, and removeEventListener automatically on unmounted
Demo
Usage
tsx
import { useEventListener } from '@reause/core'
import { useRef } from 'react'
const button = useRef<HTMLButtonElement>(null)
useEventListener(button, 'click', (evt) => {
console.log(evt)
})Every target is a React ref, and the listener is typed by that target's own event map — evt above is a PointerEvent.
Default Target
When the target is omitted, it defaults to window:
tsx
import { useEventListener } from '@reause/core'
// Listens on window
useEventListener('resize', (evt) => {
console.log(evt)
})Reactive Target
You can pass a ref as the event target, useEventListener will unregister the previous event and register the new one when the target changes:
tsx
import { useEventListener } from '@reause/core'
import { useRef } from 'react'
const element = useRef<HTMLDivElement>(null)
useEventListener(element, 'keydown', (e) => {
console.log(e.key)
})Multiple Events
You can pass an array of events to listen to multiple events at once:
tsx
const element = useRef<HTMLDivElement>(null)
useEventListener(element, ['mouseenter', 'mouseleave'], (evt) => {
console.log(evt.type)
})Multiple Targets
You can also pass an array of targets:
tsx
const first = useRef<HTMLButtonElement>(null)
const second = useRef<HTMLButtonElement>(null)
useEventListener([first, second], 'click', (evt) => {
console.log('Button clicked')
})Cleanup
Returns a cleanup function to manually unregister the listener:
tsx
const element = useRef<HTMLDivElement>(null)
const cleanup = useEventListener(element, 'keydown', (e) => {
console.log(e.key)
})
cleanup() // This will unregister the listeners.useEventListener is SSR-safe: nothing touches window during render, and binding happens in the mount effect.
Type Declarations
Toggle
ts
export type WindowEventName = keyof WindowEventMap
export type DocumentEventName = keyof DocumentEventMap
export type ShadowRootEventName = keyof ShadowRootEventMap
export interface GeneralEventListener<E = Event> {
(evt: E): void;
}
export type EventTargetRef<T> = RefObject<T | null | undefined>
export type EventTargetRefs<T> = EventTargetRef<T> | RefObject<T[] | null | undefined> | EventTargetRef<T>[]
type Arrayable<T> = T | T[]
type Fn = () => void
type EventMapOfElement<T> = T extends HTMLVideoElement ? HTMLVideoElementEventMap : T extends HTMLMediaElement ? HTMLMediaElementEventMap : T extends HTMLBodyElement ? HTMLBodyElementEventMap : T extends HTMLFrameSetElement ? HTMLFrameSetElementEventMap : T extends SVGSVGElement ? SVGSVGElementEventMap : T extends SVGElement ? SVGElementEventMap : T extends MathMLElement ? MathMLElementEventMap : HTMLElementEventMap
interface InferEventTarget<Events> {
addEventListener: (event: Events, fn?: any, options?: any) => any;
removeEventListener: (event: Events, fn?: any, options?: any) => any;
}
export function useEventListener<E extends keyof WindowEventMap>(event: Arrayable<E>, listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<E extends keyof WindowEventMap>(target: EventTargetRefs<Window>, event: Arrayable<E>, listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<E extends keyof DocumentEventMap>(target: EventTargetRefs<Document>, event: Arrayable<E>, listener: Arrayable<(this: Document, ev: DocumentEventMap[E]) => any>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<E extends keyof ShadowRootEventMap>(target: EventTargetRefs<ShadowRoot>, event: Arrayable<E>, listener: Arrayable<(this: ShadowRoot, ev: ShadowRootEventMap[E]) => any>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<T extends Element, E extends keyof EventMapOfElement<T>>(target: EventTargetRefs<T>, event: Arrayable<E>, listener: Arrayable<GeneralEventListener<EventMapOfElement<T>[E]>>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<Names extends string, EventType = Event>(target: EventTargetRefs<InferEventTarget<Names>>, event: Arrayable<Names>, listener: Arrayable<GeneralEventListener<EventType>>, options?: boolean | AddEventListenerOptions): Fn
export function useEventListener<EventType = Event>(target: EventTargetRefs<EventTarget>, event: Arrayable<string>, listener: Arrayable<GeneralEventListener<EventType>>, options?: boolean | AddEventListenerOptions): Fn