DEV Community

Mohsen Khadem Hoseini
Mohsen Khadem Hoseini

Posted on

2

EventTarget - CustomEvent | components communication in React - part Three

In the first and second parts, we focused on creating two different patterns for handling data flow in React.
In this part—and the one that follows, we’ll explore how to manage component communication using Web APIs and React’s built-in capabilities.

What is EventTarget

EventTarget is the foundation of the browser’s event system.
It’s a built-in interface that enables objects to handle events through methods like addEventListener, removeEventListener, and dispatchEvent.

Many core Web APIs including DOM elements like <button>, <div>, <input>, as well as document and window inherit from EventTarget.
That’s exactly why we can do things like:

addEventListener

How the Event system works in the browser

When we attach an event handler to a DOM element—like in the picture above—we’re actually subscribing to that element through one of its event channels.
In this case:

  • The button is the publisher (or emitter)
  • The callback function passed to addEventListener is the subscriber (or listener)

So when a user clicks the button, the button emits a 'click' event, and all registered listeners for that event type are notified and executed.

So with the EventTarget constructor, we can both publish and subscribe to built-in or custom events.
But how do we create different types of events and pass custom data with them?
That’s where the CustomEvent constructor comes in.

CustomEvent

CustomEvent allows us to define our own event types beyond the built-in types (like “click”,”change”, “keydown”) and include any kind of data through the detail property.

create custom event

After that we able to use any DOM element as the publisher for emitting this event. like this:

publishing custom event

We’re using the document as the publisher for our custom event.

And after this any listener that subscribed to document using addEventListener(“eventName”,....) will be notified.

subscribing to custom event

Good to Know: What Pattern does the Browser Event System Follow?

The event system in the browser shares similarities with both the Observer and Pub-Sub patterns.
When you attach a listener directly to a DOM element, that element acts as the subject, keeping track of its observers (callback functions). In this context, we're clearly in the Observer area.

However, when you use the EventTarget constructor to create a standalone event system not dependent on a specific DOM element—it behaves more like the Pub-Sub pattern, where publishers and subscribers are loosely coupled and communicate through named events.

The key difference between DOM-events and custom events lies in their level of coupling. Custom events are decoupled, meaning the publisher and subscriber don’t hold direct references to each other but DOM events are tightly coupled because listeners are directly attached to specific elements.

The more decoupled our communication becomes, the closer it aligns with the Pub-Sub pattern. The browser’s event system isn’t a strict implementation of either Pub-Sub or Observer, it draws inspiration from both.

Implement Custom Event System in React with EventTarget

This setup is very similar to the Pub-Sub pattern from the first article, but this time we use the browser’s built-in APIs instead of writing everything from scratch.

First, we define an EventTypes object to list all our event names and their corresponding payloads. This ensures our pub-sub implementation remains fully type-safe:

EventTypes

Later, we'll use the keys of EventTypes as event names and their corresponding values as the payloads when calling the emit function.
emit function

Next, we create an EventTarget instance. As mentioned earlier, this constructor gives us access to event-related methods like addEventListener and dispatchEvent without needing to attach them to DOM elements.

create eventTarget

Our next step is creating the emit function which allows us to publish events:
emit function

This method works similarly to the emit function we discussed in the first article. It accepts an eventName and a payload as parameters. However, this time we use the CustomEvent API to create an event instance, passing the eventName and payload as arguments. This event is then dispatched using the dispatchEvent method of the eventTarget instance, triggering the event and making it available for listeners.

Finally, we create our subscribe function, which allows us to listen to the emitted events. It takes an eventName and a callback function as parameters.

subscribe function

We defined a handler that will be executed when the event is dispatched. This function receives the event as an argument, and we pass it to a CustomEvent to access the detail property, which contains the event's data.

When you call subscribe, you're essentially telling your application to "listen" for a specific event (with a specific eventName) and provide a callback function that will be called when the event is triggered.
This sets up the handler function, but nothing happens yet. The handler function doesn't execute at this point; it's just registered to listen for events.

The subscribe function returns an unsubscribe function, which will be used later to remove the listener and prevent memory leak.

If you're interested, you can clone this repo and try out the event system yourself.

Mohsen KhademHosseini - Mohan
Linkdin
github

Top comments (0)