5 Rules to Follow When Using the Vuex Store in Components

Simon Msara
The Startup
Published in
5 min readJun 10, 2020

--

Almost everyone who has worked on a legacy application has at least once uttered the words, “Where is that coming from?!” while trying to figure out where a change to a variable originated. Unfortunately, this is not only limited to legacy applications, it is very easy to write unscalable code using modern tools. I am going to outline 5 rules I follow when creating maintainable components that make use of the Vuex store.

A working knowledge of Vuex is required to fully appreciate the rules.

We will be using the example below to illustrate the 5 points. The example shows a delivery address component that has the capability to edit the first line of the address. We will not include anything to do with errors as it’s just a different logic branch and the same principles will still apply.

1. No state management logic in components

Components should only contain logic that is limited to the scope of the component, any changes to the state should be done by committing or dispatching the relevant mutations and actions respectively.

As the address module needs to prepare itself before being edited, the component adopts the addresses’ editing state as its own and is only responsible for initiating the editing process using the startEditing action. Delegating any of the work involved in preparing the address module for editing to the component means that the logic will need to be replicated across all components that make use of the module’s editing behaviour.

Ensuring the responsibility is delegated to the appropriate party means that logic is kept in a single place and changes can be easily implemented.

2. Do not access the state directly

To ensure that state properties are always mutated and retrieved in the correct format, we never access the properties directly. Each module property should have a getter and mutation. This could make the modules more verbose but there are tools like the vuex-module-maker that reduce the workload and repetitiveness involved in creating reusable modules.

It’s worth noting that the example component does not manipulate the value of the first line of the address on retrieving or storing it, that responsibility belongs to the address module. However it would be acceptable to format the value after retrieving it if the component would be the only place where that format will be used — a filter would be best suited for the job.

3. There is no need for an EventBus!

It is difficult to debug events that are transferred via an EventBus – you know you are listening for an event but we don’t know where the event is coming from or we know we are emitting an event but we don’t know what’s listening. By removing any state management logic from components we allow different components to access and mutate the same state properties which brings with it all the necessary reactivity.

Events should be listened to on the components they are expected to be emitted from and components should only emit events up to their parents. As shown in our example, we emit an editing event after we dispatch the startEditing action; we know that we should look for the listener on the parent component. Although, as mentioned above, the parent component could also watch the address module’s editing state and get the same result.

4. Modules should be complete

A module should be able to do all that it is supposed to independently, it should have getters and mutations for all its properties and actions that provide the necessary behaviour. Having complete modules means that components should never have to be concerned with a module’s underlying functionality but rather trigger the changes and passing the required data.

Our example shows us that the component only knows to dispatch the startEditing event but it doesn’t know or care what that means, it is the address module’s responsibility to take a snap shot of the state (incase we need to cancel) and update the editing state property to true — which the component then reacts to.

The component also only knows to dispatch the submitUpdate action when saving; the module maintains the responsibility to prepare an update form, make a post request to persist the change and assuming the post is successful it will update the state with the returned value, clear the state snapshot, update editing to false.

If a change to the editing process of an address is required, all we have to do is update the module, there is no need to go around all the components that make use of the module updating logic — it’s all in one place.

5. Use reusable modules instead of objects

We tend to use the same objects with differing contexts throughout our code but the expected behaviour doesn’t really change. Take the address for example, it can be used as the primary object or it can be used in the context of a child — it can belong to a user, a company, etc. and an owner can have multiple addresses with different purposes (delivery, billing, correspondence, etc.). However, the structure and behaviour of an address remains the same.

Usually an owner will have an address object, and it’s the owner’s responsibility to ensure the address has the correct structure and behaviour. Creating a reusable address module instead means that an address can be responsible for its own behaviour leaving the context as the only variable. Instead of having an address object, a module will have a batteries-included address module – any changes that need to be made to the behaviour of an address will only need to be done once.

This does not mean that every object should be turned into a module, only objects with specific behaviour qualify to be independent modules. For example, a search module that fetches an array of objects whose purpose is simply to be displayed don’t need to be registered as modules.

In our example we can see that we are expecting an address-namespace prop to be provided, this will enable the component to access the correct address. We don’t know what context the current address is in at the moment because it doesn’t matter — it’s going to behave just like any other address and that’s the beauty of it.

Checkout the vuex-module-maker package, it makes composing reusable modules much faster and maintainable.

I would like to know some of your own rules/guidelines you follow when writing maintainable code, leave a response! 😃

--

--