This hook lets you attach one or more event listeners to the document, while avoiding re-binding cycles that are
a natural outcome of attaching handlers inside a useEffect
.
const useDocumentEvent = (events, handler) => {
const { get: getHandler } = useValue(handler);
const _handler = useCallback(e => get()(e), [get]);
useEffect(() => {
const eventsArray = events.split(' ');
eventsArray.forEach(event => document.addEventListener(event, _handler));
return () => eventsArray.forEach(event => document.removeEventListener(event, _handler));
}, [events, _handler]);
};
#Usage examples:
// Attach an event listener to the document
useDocumentEvent('resize', e => {/* Do something */});
// Attach multiple event listeners to the document
useDocumentEvent('resize scroll', e => {/* Do something */});
#Re-binding cycles in useEffect
In React, attaching event listeners is done via useEffect
because:
- You don't want to attach a new listener every render
- You need to cleanup (remove the event listener) when your component unmounts
However, if your handler is depending on external values, you need to add those to the useEffect
dependency
list, which will cause it to remove the old listener and add the new listener every time that dependency changes.
I refer to this phenomenon as "re-binding cycles".
This hook lets you avoid that.