A custom React hook for adding event listeners to one or multiple elements with flexible options.
- Supports single or multiple refs and event types.
- Handles one-to-one (element-to-event) or one-to-many mappings.
- Provides options for immediate handler execution and event listener configurations.
- Automatically cleans up listeners on unmount or dependency change.
This is a standalone hook. You can simply copy and use it from this gist in your React project.
Or you can install it using npm
:
npm i use-eventer
-
It's simply a
useEffect
that runs your code with dependencies passed. -
You can directly include all the logic you would typically use inside a
useEffect
hook, but instead, return the event handler function. -
No need for cleanup code.
import { useRef } from "react";
import useEventer from "./useEventer";
const MyComponent = () => {
const buttonRef = useRef(null);
useEventer(buttonRef, "click", () => () => {
console.log("Button clicked!");
}, []);
return <button ref={buttonRef}>Click Me</button>;
};
This hook shines when handling multiple elements, multiple events, or both, all with a shared event handler.
Also, It saves alot of cleanup code.
Here, it simply saved the cleanup code.
const divRef = useRef(null);
useEventer(divRef, "click", () => (event) => {
console.log(`Event triggered: ${event?.type}`);
}, []);
const divRef = useRef(null);
useEventer(divRef, ["mouseenter", "mouseleave"], () => (event) => {
console.log(`Event triggered: ${event?.type}`);
}, []);
const div1 = useRef(null);
const div2 = useRef(null);
useEffect(() => {
const eventHandler = () => console.log("Event triggered!");
const controller = new AbortController();
const element1 = div1.current;
const element2 = div2.current;
element1?.addEventListener("click", eventHandler, controller);
element1?.addEventListener("mouseenter", eventHandler, controller);
element2?.addEventListener("click", eventHandler, controller);
element2?.addEventListener("mouseenter", eventHandler, controller);
return () => {
controller.abort();
};
}, []);
const div1 = useRef(null);
const div2 = useRef(null);
useEventer([div1, div2], ["click", "mouseenter"], () => () => {
console.log("Event triggered!");
}, []);
By default, oneToOne
is set to false
, meaning each div
will have both event listeners attached. If oneToOne
is set to true
, each div
will only have the event listener corresponding to its order.
Sometimes, you may need to add some logic (and maybe with dependencies) before event attachment. You can add it in the callback passed, and then return the event handler.
const divRef = useRef(null);
useEffect(() => {
console.log("color changed");
const eventHandler = (event) => {
console.log(`color is: ${color}`);
};
const element = divRef.current;
element?.addEventListener("click", eventHandler);
return () => {
element?.removeEventListener("click", eventHandler);
};
}, [color]);
const divRef = useRef(null);
useEventer(divRef, "click", () => {
console.log("color changed");
return (event) => {
console.log(`color is: ${color}`);
};
}, [color]);
useEventer
is simply a useEffect
, but you can add your event listeners with shared dependencies to save lines of code.
- The hook automatically removes event listeners when the component unmounts.
- If
dependencies
change, listeners are re-registered accordingly. - The
AbortController
is used for efficient cleanup. - You can pass a
signal
to the event listener for your custom use, but in this case, cleanup function will not use theAbortController
. Instead, it will manually remove all listeners.
Throws an error if oneToOne
is true
but the number of refs and events don't match.
Parameter | Type | Description |
---|---|---|
ref |
RefObject<T> | RefObject<T>[] |
A single or array of refs pointing to elements. |
event |
string | string[] |
The event type(s) to listen for. |
callback |
() => EventListenerCallback |
A function returning the event handler. |
dependencies |
any[] (optional, default: [] )
|
Dependencies for useEffect . |
options |
HookOptions (optional, default: {} )
|
Additional configuration options. |
Option | Type | Default | Description |
---|---|---|---|
oneToOne |
boolean |
false |
If true , each event applies to a single corresponding element. Otherwise, all events apply to all elements. |
callHandlerOnce |
boolean |
false |
If true , the handler is called once immediately after setup. |
callHandlerOnEach |
boolean |
false |
If true , the handler is called on each event binding. |
listenerOptions |
AddEventListenerOptions |
{} |
Additional options for the event listener. |
- The callback must return an event listener function.
- The
listenerOptions
allow passing options likepassive
,capture
, oronce
.
This hook provides a simple and flexible way to manage event listeners in React. 🚀