Architect state management in a large scale Vue.js application
Now a days, web application are more complex & dynamic and has to deal with a large amount of data along with intuitive and interactive user experience. So, state management has become one of the important decision that has to make by the developer at the time of architecting the application.
This article is 3rd part of the series Architect a large scale Vue.js Application . You can find the supporting boilerplate here. In this, I am going to explain, how should we architect the state of our application.
Vue.js provides its own official state management pattern + library
named as Vuex
and it is one of the most recommended library that should be used for state management in Vue.js applications. Here, I will not go deep into the Vuex
core concepts such as what is vuex
, mutations,
or actions
etc. I will write another separate article explaining them in detail.
When we talk about the state in a component based application, then it is generally of 2 types:
- Component local state, limited to just in the scope of component,
- Application level state, shared across the application components
Some people suggests, we should keep all the state (local + global) on the application store and while other suggests local states of component should be managed by the component itself rather than keeping all the state (local + global) on application store. I feels that, 2nd approach is the good way to manage the state, it keeps the application store more cleaner and manageable.
Now, the question is, application could be very large & complex and needs to manage huge amount of data flow, then in this case how should we organise the application state? The simple answer is, in a modular
way. You remember, in the first article, we organised the application into multiple feature modules
. In the same way, we will organise the application state on feature level and each feature module
will be responsible for managing the related states.
In the project structure, each feature module has a shared/state
folder. This is where, we will keep all the state files related to that feature module. For eg. user feature module
will have its state files in users/shared/state
and suppose it will have states such as user list data, user details, etc. then we will create one file for each state, let’s say, for user list data we created users-data.js
under users/shared/state
and each file looks like below:
There are few things, I would like to explain about the above code snippets:
- I did put all the
mutations,
actions
& relatedconstants
in a single file as these are linked to each other. Also, we can have them in separate files but I thought, it would be good to have these in a single file. reflectKeys
is just a method which mirrors the keys i.e. it returns anobject
with supplied string askey
andvalue
. Also, we can add a prefix to key values as well. It is just used for managing theconstants
string formutation types
andaction types
rather than hardcoding the strings.Vuex
provides its own way tonamespace
thestate
,mutations,
actions
, etc. but I am using other way tonamespace
by usingprefix
. I found it as more comfortable and convenient because we don’t need to addnamespace
part everywhere for callingactions
,mutations
orstate getters
etc. But as per your interest, you can usevuex namespace
.- In
Vuex
, we can commit themutations
directly without havingactions
. We needactions
in theasync
operations. I suggest, useactions
instead of committing themutations
directly, for bothsync
andasync
operations. You can see, I just exportedaction types
notmutation types
. This is because, it will maintain the consistency, onlyactions
will be responsible for triggering the state updates. - As you can see,
actions
are just committing the mutations, all the business logic, for eg.API
calling as been moved toservices
. In the same way, we need to maintain the actions more clean and having the business logic intoservices
. This makes the application more flexible by having a clear separation into the business logic and state management.
Each feature module
has a state file at the root of that module. This file is responsible for combining all the states of that feature module
. For eg. in our case, it issrc/app/users/user-state.js
. We are using Vuex
modules to combine all the states of this feature module
and looks like below:
In the same way, all feature modules
state will be combined into the application state using the same concepts i.e. Vuex modules
. For eg. src/app/app-state.js
will look like below:
You can see that, I am importing the usersState
from users feature module
.
There will also be cases in which we need to share states across different feature modules
. These type of state can be defined into the app/shared/state
and then needs to be integrated into application state as well.
I prepared the boilerplate around this architecture. You can find it here https://github.com/arunredhu/vuejs_boilerplate. I look forward to see your contribution.
Conclusion:
State management in a large scale application is very challenging and needs to have a well defined architecture. The architecture explained in this article is general and working for me in many large applications but it could vary based on the type of the application and developer needs.