|
@@ -0,0 +1,37 @@
|
|
|
|
+import { useEffect, useRef } from 'react'
|
|
|
|
+
|
|
|
|
+type EventType = keyof WindowEventMap | keyof DocumentEventMap
|
|
|
|
+type EventHandler<E extends Event> = (event: E) => void
|
|
|
|
+type EventOptions = boolean | AddEventListenerOptions
|
|
|
|
+
|
|
|
|
+function useEventListener<E extends Event>(
|
|
|
|
+ eventName: EventType,
|
|
|
|
+ handler: EventHandler<E>,
|
|
|
|
+ element?: HTMLElement | Window | Document | null,
|
|
|
|
+ options?: EventOptions
|
|
|
|
+) {
|
|
|
|
+ const savedHandler = useRef<EventHandler<E>>(handler)
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ savedHandler.current = handler
|
|
|
|
+ }, [handler])
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const target = element ?? window
|
|
|
|
+ if (!(target && target.addEventListener)) return
|
|
|
|
+
|
|
|
|
+ const eventListener = (event: Event) => {
|
|
|
|
+ if (savedHandler.current) {
|
|
|
|
+ savedHandler.current(event as E)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ target.addEventListener(eventName, eventListener, options)
|
|
|
|
+
|
|
|
|
+ return () => {
|
|
|
|
+ target.removeEventListener(eventName, eventListener, options)
|
|
|
|
+ }
|
|
|
|
+ }, [eventName, element, options])
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export default useEventListener
|