useEventListener
一个用于添加事件监听器的 React Hook,支持多种目标元素和事件类型。
功能特性
- ✅ 事件监听: 简化事件监听器的添加和移除
- ✅ 多目标支持: 支持 DOM 元素、window、document 等
- ✅ 自动清理: 组件卸载时自动移除监听器
- ✅ 类型安全: 完整的 TypeScript 类型支持
基本用法
typescript
import useEventListener from "./useEventListener";
function Component() {
useEventListener("click", (event) => {
console.log("Window clicked:", event);
});
const buttonRef = useRef(null);
useEventListener(
"click",
(event) => {
console.log("Button clicked:", event);
},
buttonRef
);
return <button ref={buttonRef}>点击我</button>;
}兼容性
- ✅ React 16.8+
- ✅ TypeScript 4.0+
- ✅ 现代浏览器
实现源码
查看 useEventListener 的实现
tsx
import { useEffect, useRef } from "react";
import type { RefObject } from "react";
import { useIsomorphicLayoutEffect } from "../useIsomorphicEffect";
function useEventListener<K extends keyof MediaQueryListEventMap>(
eventName: K,
handler: (event: MediaQueryListEventMap[K]) => void,
element: RefObject<MediaQueryList>,
options?: boolean | AddEventListenerOptions
): void;
function useEventListener<K extends keyof WindowEventMap>(
eventName: K,
handler: (event: WindowEventMap[K]) => void,
element?: undefined,
options?: boolean | AddEventListenerOptions
): void;
function useEventListener<
K extends keyof HTMLElementEventMap & keyof SVGElementEventMap,
T extends Element = K extends keyof HTMLElementEventMap
? HTMLDivElement
: SVGAElement
>(
eventName: K,
handler:
| ((event: HTMLElementEventMap[K]) => void)
| ((event: SVGElementEventMap[K]) => void),
element?: RefObject<T>,
options?: boolean | AddEventListenerOptions
): void;
function useEventListener<K extends keyof DocumentEventMap>(
eventName: K,
handler: (event: DocumentEventMap[K]) => void,
element?: undefined,
options?: boolean | AddEventListenerOptions
): void;
function useEventListener<
KW extends keyof WindowEventMap,
KH extends keyof HTMLElementEventMap & keyof SVGElementEventMap,
KM extends keyof MediaQueryListEventMap,
T extends HTMLElement | SVGAElement | MediaQueryList = HTMLElement
>(
eventName: KW | KH | KM,
handler: (
event:
| WindowEventMap[KW]
| HTMLElementEventMap[KH]
| SVGElementEventMap[KH]
| MediaQueryListEventMap[KM]
| Event
) => void,
element?: RefObject<T>,
options?: boolean | AddEventListenerOptions
) {
const saveHandler = useRef(handler);
useIsomorphicLayoutEffect(() => {
saveHandler.current = handler;
}, [handler]);
useEffect(() => {
const targetElement: T | Window = element?.current ?? window;
if (!(targetElement && targetElement.addEventListener)) {
return;
}
const listener: typeof handler = (event) => {
saveHandler.current(event);
};
targetElement.addEventListener(eventName, listener, options);
return () => {
targetElement.removeEventListener(eventName, listener, options);
};
}, [eventName, element, options]);
}
export default useEventListener;