use-event-listener (use-event-listener)
A React hook for managing DOM event listeners with proper cleanup.
v0.1.0
Usage
import { use-event-listener } from "@/hooks"
1"use client";
2
3import React, { useRef, useState } from "react";
4
5import { Badge } from "@/components/ui/badge";
6import { Button } from "@/components/ui/button";
7import {
8 Card,
9 CardContent,
10 CardFooter,
11 CardHeader,
12 CardTitle,
13} from "@/components/ui/card";
14
15import { useEventListener } from "@/components/hooks/use-event-listener";
16
17export function UseEventListenerDemo() {
18 // State for window events
19 const [windowMousePosition, setWindowMousePosition] = useState({
20 x: 0,
21 y: 0,
22 });
23 const [windowScroll, setWindowScroll] = useState(0);
24
25 // State for element-specific events
26 const [clickCount, setClickCount] = useState(0);
27 const [isHovering, setIsHovering] = useState(false);
28
29 // Reference for the element we want to track
30 const buttonRef = useRef<HTMLButtonElement>(null);
31
32 // Track mouse position across the window
33 useEventListener({
34 eventName: "mousemove",
35 handler: (event) => {
36 setWindowMousePosition({
37 x: event.clientX,
38 y: event.clientY,
39 });
40 },
41 });
42
43 // Track window scroll position
44 useEventListener({
45 eventName: "scroll",
46 handler: () => {
47 setWindowScroll(window.scrollY);
48 },
49 });
50
51 // Track clicks on a specific element
52 useEventListener<"click", HTMLButtonElement>({
53 eventName: "click",
54 handler: () => setClickCount((prev) => prev + 1),
55 element: buttonRef,
56 });
57
58 // Track mouse enter/leave on element
59 useEventListener<"mouseenter", HTMLButtonElement>({
60 eventName: "mouseenter",
61 handler: () => setIsHovering(true),
62 element: buttonRef,
63 });
64
65 useEventListener<"mouseleave", HTMLButtonElement>({
66 eventName: "mouseleave",
67 handler: () => setIsHovering(false),
68 element: buttonRef,
69 });
70
71 return (
72 <div className="space-y-4">
73 <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
74 <Card className="max-w-sm w-full">
75 <CardHeader>
76 <CardTitle>Window Events</CardTitle>
77 </CardHeader>
78 <CardContent className="space-y-2">
79 <p className="font-medium">Mouse Position: </p>
80 <Badge variant="secondary">
81 X: {windowMousePosition.x}, Y: {windowMousePosition.y}
82 </Badge>
83 <p className="font-medium">Scroll Position: </p>
84 <Badge variant="secondary">{windowScroll}px</Badge>
85 </CardContent>
86 </Card>
87
88 <Card className="max-w-sm w-full">
89 <CardHeader>
90 <CardTitle>Element Events</CardTitle>
91 </CardHeader>
92 <CardContent className="space-y-2">
93 <div>
94 <span className="font-medium">Click Count: </span>
95 <Badge variant="secondary">{clickCount}</Badge>
96 </div>
97 <div>
98 <span className="font-medium">Hover State: </span>
99 <Badge variant={isHovering ? "default" : "secondary"}>
100 {isHovering ? "Hovering" : "Not Hovering"}
101 </Badge>
102 </div>
103 </CardContent>
104 <CardFooter>
105 <Button
106 ref={buttonRef}
107 className={`mt-2 ${isHovering ? "bg-primary-foreground" : ""}`}
108 >
109 Click Me
110 </Button>
111 </CardFooter>
112 </Card>
113 </div>
114
115 <div className="text-sm text-muted-foreground">
116 Try moving your mouse, scrolling, or interacting with the button above.
117 </div>
118 </div>
119 );
120}
121
Install
npx wkkkis-hooks add use-event-listener
Options
Name | Type | Default | Description |
---|---|---|---|
eventName | keyof WindowEventMap | Required | The DOM event name to listen for |
handler | (event: Event) => void | Required | The callback function for the event |
element | RefObject<HTMLElement> | EventTarget | window | The element to attach the listener to |
options | boolean | AddEventListenerOptions | undefined | Options for addEventListener |
Features
- useEventListener provides a clean, type-safe way to manage DOM event listeners in React components with these benefits:
- Automatically handles cleanup on unmount to prevent memory leaks
- Preserves handler reference between renders with a ref
- Type-safe event names and handler parameters
- Works with window, document, or specific DOM elements
- Supports all AddEventListener options
Browser Support
- This hook relies on the standard DOM addEventListener API, which is supported in all modern browsers:
- Chrome: Full support
- Firefox: Full support
- Safari: Full support
- Edge: Full support
- Opera: Full support
Performance Considerations
- Uses useRef to avoid recreating event listeners on each render
- Minimizes re-renders by not returning state
- Automatic cleanup prevents memory leaks
- Minimal overhead compared to direct event listeners
Best Practices & Caveats
- Always provide a stable handler or use useCallback for the event handler
- For element refs, ensure the element is mounted before the hook runs
- For high-frequency events like mousemove or scroll, consider debouncing or throttling
- TypeScript users benefit from complete type safety for events
- Be cautious with passive events on touch devices for performance
Files in this hook
Source | Destination |
---|---|
files/use-event-listener.ts | src/hooks/use-event-listener.ts |