A journey from the EventBus pattern to Vuex architecture
There are many reasons to use Vuex on the top of Vue.js, and most of them are well discussed.
What I want to propose in this article, is a different point of view on what is Vuex and why it is useful.
Let’s begin our journey from the EventBus pattern. What is an EventBus? Many people confuse the EventBus with the Observable pattern. An EventBus can be seen as a collection of observable events. If you need a definition: EventBus is an special Publish & Subscribe Pattern implementation.
By using an EventBus, modules can register to certain events and can publish their own events. Some people think that by using an EventBus we can isolate modules and make them unaware of the existence of the other modules. Even though the EventBus helps to create loosely coupled modules, it does not make a module independent from another one.
Think of it: in order to register to an event, you must know the event to register to and the corresponding payload. If you use a strongly typed language, it is easier to understand what I am saying. When you register to an event, you must import the event class. Also, events usually comes with some data related. This event data is commonly referred as payload. To use the payload you must import the payload interface. Using strings for events name and unstructured data, such as Maps, for payload is not a good solution.
One benefit of using this pattern is that modules needs to depend just on other module contracts (interfaces) and not on concrete classes. This means that a module can listen to an event without knowing which component will publish the event.
A pure event based architecture has some intrinsic problems that cannot be resolved, unless you evolve this architecture in something more powerful. Those problems are:
- Determine the initial state of a component.
- Registering to an event after it has been dispatched.
Let’s make an example:
Say that you have a (web) page where there is a chat, and, elsewhere, the number of new messages you haven’t read yet. A simple implementation could be:
// ChatComponent.js
chat.onfocus = () => eventBus.post('CHAT_FOCUS');
chat.onblur = () => eventBus.post('CHAT_BLUR');// UnreadCounter.js
let unreadCounter = 0;
let chatHasFocus = false;eventBus.on('NEW_MESSAGE', () => {
if(!chatHasFocus) {
unreadCounter++;
}
});eventBus.on(‘CHAT_FOCUS’, () => {
chatHasFocus = true;
unreadCounter = 0;
});eventBus.on(‘CHAT_BLUR’, () => chatHasFocus = false);
In the above example, each time the user selects the chat, the number of unread messages is set to 0. Each time there is a new message and the chat is not selected, the number of unread messages is increased.
How can the UreadCounter know that the initial state of the chat is unfocused and the number of unread messages is 0? What if the user reloads the page and there were 3 unread messages?
Is the event CHAT_FOCUS the only event that implies the user read some or all the messages?
When we use a pure event based architecture, components have to deduce application state from events and it is hard to know the initial values. They also need to know every event that may change the state they are observing.
Wouldn’t it be better to have an explicit application state? Wouldn’t it be easier if every value in the state is mutated in a predictable fashion?
FaceBook engineers faced similar problems and created what they called “Flux: application architecture for building user interfaces”.
Of course Flux is not just an evolution of the EventBus pattern, it is a whole MVC application architecture. Vuex can be considered the Flux architecture for Vue.js. There are other implementations of Flux like Redux for React or NgStore for Angular.
In Vuex there is only one store per application. All the application state is contained inside the store. Components can read the state and get notified when the state changes. This solves the problems introduced earlier. A component doesn’t need to infer the current value of a property of the state, because it can simply read it from the store. It doesn’t need to listen to events either, each time the property is changed, it gets notified.
But, what about changing the application state? In that case the application store acts like an event bus: a component can dispatch an action and the corresponding action handler is executed. This means that only the store contains the code to be executed because of an action, preventing application logic to be spread inside components.
If you are now interested in understanding better what Vuex is, you can visit its website: https://vuex.vuejs.org/. Or, better, you can read my book: Vuex Quick Start Guide. You can buy it on Amazon or on Packt web site.