• Skip to main content
  • Skip to primary sidebar
BMA

BeMyAficionado

Inspire Affection

Event Driven Communication Between Domains/Components – Frontend Development

May 8, 2023 by varunshrivastava Leave a Comment

Event Driven Architecture has been around for decades. This is not something new that we discovered recently. But we have definitely seen the rise of this with the emergence of distributed system and need for asynchronous communication.

Event Driven Architecture really helps to reduce the complexity involved with distributed system while providing a way to asynchronously communicate with each other. This helps in making the application more modular (since there is no coupling involved), more reactive and easy to scale.

When I tried explaining the EDA using Event Bus to my colleague, I got a question, asking “How is it different than redux state management?”. Since in redux one component updates the state and then the other component listen to the state and updates itself. Well, these two are completely different mechanism. Redux is a centralized state management system whilst Event Bus is a communication mechanism.

Table of Contents

    • How Event Bus Different From Redux State Management System
      • Immediate Benefits Of Using Separate Event System For Communication
    • How Event Driven Communication Different than a Direct Method Call?
    • Implement Event Driven Communication Using Custom Event Bus (React/Typescript)
      • Create a Singleton for Event Bus
      • Subscribe To Topics
      • Publish Events to Topics
      • Remove Subscribers
    • Implement Event Driven Communication Using Broadcast Channel (React/Typescript)
    • Event Bus in Action
  • Conclusion

How Event Bus Different From Redux State Management System

You might be right in thinking that both Event Bus and Redux are doing the similar thing – they are both managing state of the of the application. But you might be overlooking the fact that they are serving two completely different purpose.

I get the confusion though, since Redux and Event Bus both are based on the Event Driven Architecture. The subtleties are in the purpose for which they are built for.

The Event Bus is a way for different components of an application to communicate with each other through events, while Redux is a state management tool that provides a centralized store for an application’s state.

In an event-driven system, each component can publish events that other components can subscribe to, and when an event is published, all subscribed components are notified and can react accordingly. This makes the application more modular and easier to maintain, as components are decoupled from each other and can react to events independently. On the other hand, Redux provides a centralized store for an application’s state, making it easier to manage and access the state across different components. While both event-driven communication and Redux can be used in the same application, they serve different purposes and can be used to solve different problems.

Immediate Benefits Of Using Separate Event System For Communication

There are many benefits to separating out the Event System from state management. Some of them are as follows:

You don’t always need state to change based on an event
Whilst it is common for state to be changed in response to an event you don’t always need to connect state change with an event. Sometimes all that is needed is to start an asynchronous background process and have it report when it is done. Bringing external state in where it is not required leads to added complexity and overhead.

You have limited your dependency exposure to a small simple component
An eventing system will become a major dependency hazard for any large app as every component that has to communicate with another will need to have access to an instance of your event dispatcher. By using a separate Event System we have avoided automatically connected state management to all your app components.

You can manage asynchronicity however you like
Events are no longer tied to state change so async becomes easier. Want to use an async function to manage asynchronous events? Easy. You control how asynchronicity is managed and what state dependencies you have available.

For a detailed view, I recommend reading following article:

  • Life After Redux

How Event Driven Communication Different than a Direct Method Call?

First of all Event Driven communication is asynchronous. That means it doesn’t wait for other components to return or do something. It fires and forget kinda of mechanism. Another thing is that it doesn’t know about the other component who might be using the events raised by this component. Thus resulting in a structure that is completely decoupled from one another and hence highly modular and manageable.

Whereas direct method call means that one component invokes the method of the other component. Therefore, component one knows about the other component and this creates a tight coupling.

In event driven components creates events that is published to the central event system or event bus, then event bus pass the events to all its subscribers. This is how it will look like in a diagram:

If you have been working in frontend, you are used to working with events. Events such as onPageLoad, onClick, onChange etc. You consume these events and provide certain functionalities to it. It is similar to that. This makes your application reactive and allows for seamless and responsive user experience where changes in data and user input are reflected in near real time.

Implement Event Driven Communication Using Custom Event Bus (React/Typescript)

When I faced the situation to implement this architecture, I directly started by writing a small lightweight event bus. Because I knew the concept beforehand 😀

And I think that is the best way to learn and understand how event bus works.

So, event bus simply follows the pattern of Publisher/Subscriber.

It means that there will be two group of users,

  1. Publishers
  2. Subscribers

Publishers are the ones who will be creating events. These events will then be published to the event bus.

Subscribers are the receivers of the events. The events published by the publishers are received by the receivers on the other side of the event bus. And Event Bus acts as the medium to transport these messages from publishers to the subscribers.

With that said, let’s implement a very simple light weight event bus.

export interface Subscriber {
    name: string
    callback: (data: any) => void
}

class EventBus {
    private static instance: EventBus | undefined
    private subscribers: Map<string, Array<Subscriber>>

    constructor() {
        this.subscribers = new Map();
    }

    public static getInstance() {
        if (EventBus.instance === undefined) {
            EventBus.instance = new EventBus();
        }

        return EventBus.instance;
    }

    public async publish(topicName: string, data: any) {
        let subscribers = this.subscribers.get(topicName);
        console.log(subscribers);

        subscribers!.forEach(s => s.callback(data));

    }

    public async subscribe(topicName: string, subscriber: Subscriber) {
        if (!this.subscribers.has(topicName)) {
            this.subscribers.set(topicName, []);
        }

        let subscriberList = this.subscribers.get(topicName);
        subscriberList!.push(subscriber);
    }

    public async remove(topicName: string, subscriberName: string) {
        let subscriberList = this.subscribers.get(topicName)!;
        this.subscribers.set(topicName, subscriberList.filter(s => s.name !== subscriberName))
    }
}

export default EventBus;

Woah, I pasted everything at once 😀

Let’s go through each section one-by-one.

Create a Singleton for Event Bus

Creating a singleton class for event bus will ensure that there is only one instance of EventBus at all time. And that instance will be shared across all the component in the application. This way you can make sure that all components are using the same event bus to receive the message.

class EventBus {
    private static instance: EventBus | undefined
    private subscribers: Map<string, Array<Subscriber>>

    constructor() {
        this.subscribers = new Map();
    }

    public static getInstance() {
        if (EventBus.instance === undefined) {
            EventBus.instance = new EventBus();
        }

        return EventBus.instance;
    }
.
.
.

Subscribe To Topics

The following piece of code takes in the topic name and subscriber info to add it to a topic’s list of subscribers. Once the subscriber invokes this method, their information is persisted in memory.

    private subscribers: Map<string, Array<Subscriber>>
.
.
.
    public async subscribe(topicName: string, subscriber: Subscriber) {
        if (!this.subscribers.has(topicName)) {
            this.subscribers.set(topicName, []);
        }

        let subscriberList = this.subscribers.get(topicName);
        subscriberList!.push(subscriber);
    }

Publish Events to Topics

When the publisher calls this method, they pass the topic name (where they want to publish message) along with the data. Then this method is responsible to get all the subscribers for the given topic and pass the data to them.

The following code is responsible for that:

    private subscribers: Map<string, Array<Subscriber>>
.
.
.
    public async publish(topicName: string, data: any) {
        let subscribers = this.subscribers.get(topicName);
        console.log(subscribers);

        subscribers!.forEach(s => s.callback(data));

    }

Remove Subscribers

When the page is unmounted then we need a way for the components to un-subscribe themselves. This is needed because when they are not active, it is not useful for them to receive the message.

Also, it could create some side-effects and unwanted behaviour. So, its better to unsubscribe when the component un-mounts.

And for that we need to provide them with the way to let event bus know that they are no longer the subscribers.

The following code un-subscribers the given subscriber from the list by their name:

    public async remove(topicName: string, subscriberName: string) {
        let subscriberList = this.subscribers.get(topicName)!;
        this.subscribers.set(topicName, subscriberList.filter(s => s.name !== subscriberName))
    }

There is another way of using the event bus which is provided in all modern browsers. That is called the Broadcast Channel API.

Implement Event Driven Communication Using Broadcast Channel (React/Typescript)

Now-a-days there is an inbuilt BroadcastChannel API that is offered by every modern browser. This API is quite powerful, unlike the Custom Event Bus that we created the above example, the Broadcast Channel API allows different tabs or windows of the same origin to communicate with each other through messages.

It is extremely simple to use as well. All you have to do is create an instance of the BroadcastChannel and pass the topic name to it. Then you can use it in your application. You can create multiple instances of the BroadcastChannel (it need not be singleton) and then use them to communicate over the channel.

Here’s the sample example on how to use Broadcast API.

// Connection to a broadcast channel
const bc = new BroadcastChannel("test_channel");

// Example of sending of a very simple message
bc.postMessage("This is a test message.");

// A handler that only logs the event to the console:
bc.onmessage = (event) => {
  console.log(event);
};

// Disconnect the channel
bc.close();

In order to replace use Broadcast Channel instead of custom event bus, simply replace the subscriber code as following:

    useEffect(() => {
        const channel = new BroadcastChannel("channel:topic");
        channel.onmessage = (event: any) => {
            console.log("Event Data: ", event);
            if (event.data !== null)
                // update state or do something with the data
        }
    }, [])

And to post the message, do the following:

const Component: React.FC = () => {
    const channel = useMemo(() => new BroadcastChannel("channel:topic"), []);
    
    const onSomeChangeEvent = (e) => {
        channel.postMessage(e.target.value);
    }    
.
.
.
}

It is that simple.

Just be caution because this will work across tabs and browser windows on same origin. So, just make sure you want this functionality in your application.

Event Bus in Action

I created a following page to demonstrate the use of Event Driven Communication between components. I’ve taken an example of a demo Machine Health Viewer where there are multiple assets that needs to be filtered on the basis of some location.

In the page below, there are two components:

  1. Asset Filter
  2. Asset List View

As soon as we change the asset filter, an event is published to the event bus on FILTER topic. This event is then relayed to the subscriber (Asset List Viewer) by the event bus. And then Asset List Viewer component updates the list accordingly.

Demo Asset Filter

On changing the filter, Asset List View is changed as well. This happens completely asynchronously and de-coupled way. Here, Asset Filter component doesn’t even know that Asset List View exists and vice-versa. They are simply reacting to the events they receive without know who sends the events.

Demo Event Driven Communication Frontend using Event Bus

Here’s the entire code for the above demo. Make sure to copy the code correctly. Also, I replaced my custom event bus with the PostalJS. If you want to use the above event bus then update the code accordingly.

Conclusion

In conclusion, event-driven communication is an important concept in frontend development, particularly in the context of building scalable and reactive web applications.

With event-driven communication, different components of an application can communicate with each other through events, simplifying communication and making the application more modular and easier to maintain.

In this blog post, we discussed the concept of event-driven communication and its benefits, and illustrated how it can be implemented in React TypeScript using a simple use-case of Filter and View. I hope that this blog post has provided you with a better understanding of event-driven communication and its importance in frontend development, and encourages you to consider using it in your own projects.

I’m always reading my comments, so feel free to drop by if you have any queries or suggestions.

Related

Filed Under: Programming Tagged With: event-bus, event-driven-communication, programming, react, typescript

Primary Sidebar

Subscribe to Blog via Email

Do you enjoy the content? Feel free to leave your email with me to receive new content straight to your inbox. I'm an engineer, you can trust me :)

Join 874 other subscribers

Latest Podcasts

Recent Posts

  • Is The Cosmos a Vast Computation?
  • Building Semantic Search for E-commerce Using Product Embeddings and OpenSearch
  • Leader Election with ZooKeeper: Simplifying Distributed Systems Management
  • AWS Serverless Event Driven Data Ingestion from Multiple and Diverse Sources
  • A Step-by-Step Guide to Deploy a Static Website with CloudFront and S3 Using CDK Behind A Custom Domain

Recent Comments

  • Varun Shrivastava on Deploy Lambda Function and API Gateway With Terraform
  • Vaibhav Shrivastava on Deploy Lambda Function and API Gateway With Terraform
  • Varun Shrivastava on Should Girls Wear Short Clothes?
  • D on Should Girls Wear Short Clothes?
  • disqus_X5PikVsRAg on Basic Calculator Leetcode Problem Using Object-Oriented Programming In Java

Categories

  • Blogging
  • Cooking
  • Fashion
  • Finance & Money
  • Programming
  • Reviews
  • Software Quality Assurance
  • Technology
  • Travelling
  • Tutorials
  • Web Hosting
  • Wordpress N SEO

Archives

  • November 2024
  • September 2024
  • July 2024
  • April 2024
  • February 2024
  • November 2023
  • June 2023
  • May 2023
  • April 2023
  • August 2022
  • May 2022
  • April 2022
  • February 2022
  • January 2022
  • November 2021
  • September 2021
  • August 2021
  • June 2021
  • May 2021
  • April 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • February 2020
  • December 2019
  • November 2019
  • October 2019
  • August 2019
  • July 2019
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • January 2019
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • March 2018
  • February 2018
  • January 2018
  • December 2017
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • July 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • September 2016
  • August 2016
  • July 2016
  • June 2016
  • May 2016

Tags

Affordable Hosting (4) algorithms (4) amazon (3) aoc-2020 (7) believe in yourself (4) best (4) database (4) earn money blogging (5) education (4) elementary sorting algorithms (4) experience (3) fashion (4) finance (6) Financial Freedom (7) food (7) friends (3) goals (5) google (5) india (10) indian cuisine (5) indian education system (4) java (16) life (16) life changing (4) love (4) make money (3) microservices (9) motivation (4) oops (4) podcast (6) poor education system (4) principles of microservices (5) problem-solving (7) programmer (5) programming (28) python (5) reality (3) seo (6) spring (3) success (10) success factor (4) technology (4) top 5 (7) typescript (3) wordpress (7)

Copyright © 2025 · Be My Aficionado · WordPress · Log in

Go to mobile version