wkkkis-hooks

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

NameTypeDefaultDescription
eventNamekeyof WindowEventMapRequiredThe DOM event name to listen for
handler(event: Event) => voidRequiredThe callback function for the event
elementRefObject<HTMLElement> | EventTargetwindowThe element to attach the listener to
optionsboolean | AddEventListenerOptionsundefinedOptions 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

SourceDestination
files/use-event-listener.tssrc/hooks/use-event-listener.ts