Skip to main content
useSubscription attaches an event listener to a source and automatically detaches it when the component unmounts or when the source, event name, or handler changes. It works with both DOM EventTarget objects and Node-style EventEmitter instances, giving you a single primitive for all event-driven subscriptions.

Signature

useSubscription({ source, event, handler })

Parameters

source
EventTarget | EventEmitter
required
The object to listen to. This can be any DOM EventTarget (such as window, document, or a DOM element) or a Node-style EventEmitter that exposes .on() and .off() methods.
event
string
required
The event name to listen for, such as 'resize', 'click', or 'message'.
handler
function
required
The callback function to attach. Solar passes this directly to addEventListener or .on().

How it works

On the first render, useSubscription calls addEventListener(event, handler) for DOM sources or .on(event, handler) for Node emitters. On subsequent renders, it re-attaches only if source, event, or handler has changed — otherwise the existing listener stays in place. When the component unmounts, Solar calls removeEventListener or .off() automatically to clean up.

Examples

// Window resize
const [width, setWidth] = useState(window.innerWidth)
useSubscription({
  source: window,
  event: 'resize',
  handler: () => setWidth(window.innerWidth),
})

// DOM element click
const buttonRef = document.getElementById('my-btn')
useSubscription({
  source: buttonRef,
  event: 'click',
  handler: handleClick,
})
If you define your handler inline in render(), it becomes a new function reference on every render, which causes useSubscription to detach and re-attach the listener on every render. For best performance, define the handler outside render() or wrap it with useMemo so the reference stays stable across renders.