A New Way to Write Vuex Module
Since I have started using Vuex I feel that there is a big mistake in the modules feature. Let’s talk about it and what I have done about it.
First of all, this post is to explore the reasons why I have written the vue-tools package.
What I think is Wrong with Vuex Module?
Into Vuex’s documentation page, to dispatch a module’s action we had to pass the module name and the action name as action type, like:
store.dispatch(‘module/action’)
Looks great and simple, right?! but there are some big issues:
- Wich argument that action is expecting?
- Where is this action implementation?
In the real world, with many developers working on a fast-growing project we have to rename modules; move codes and files; delete things that we don't need any longer. When dealing with code refactoring, we will find out that the hardest job is finding all references and uses of getters and actions. Even using typescript and modern code editors won’t help you in anything.
To work on those problems I have seen people creating modules like this:
I agree that this solves the code reference problem, but it is ugly! I think so. Imagine that there are many actions and mutations in a real word module to change loading and errors flags.
With these problems in mind, I had started my research for packages that come up with a new approach to define the Vuex modules. I found just one: vuex-module-decorators. It uses class and decorators to define modules. It's a good way to do it, but I don't like to use class. Personally, I prefer a functional style, even Vue 3 will use functional methods -the composition API- to create the component instance.
My Proposal to Solve Those Problems
My package vuex-tools solve it and also, make it easier to create modules. take a look:
Don't forget to read the comments. has a lot of explanations too.
If you are fast, you already noticed that using typescript and a modern code editor is advantageous for you. let’s highlight some points:
- Easy goto implementation just by vscode control+clicking into the function name.
- Easily find all uses of an action;
- Type for actions arguments and mutations also getters (more about getter later);
- All state type in just one place.
As you have seen, my package just have two functions createModule
and createState
. The first one is the heart of this package because it implements the interface ModuleBuilder, it’s an API to create an module
incrementally. And createState
builds modules and creates an instance of the Vuex Store as you are used to.
The interface ModuleBuilder have 3 functions that you can use: action
, mutation
and getter
. I think you know what they can do for you. action
and mutation
return another function that expects an argument (or not) and returns an object. This return is passed to store$dispatch
or store$commit
and Vuex will know what to do with it. getter
is different, look how to use it:
const getSortedItems = moduleBuilder.getter<Item[]>(
'sortedItems',
(state) => [...state.items].sort(a, b) => a.order - b.order
);
// vue component
{
computed: {
sortedItems() {
getSortedItems(this.$store.getters)
}
}
}
We pass the store$getter
to returned function of ModuleBuilder$getter
call, and it returns the getter value.
If you have read this far, thank you very much! And I would be glad to have your clap and feedback about what I have done, also I am open to answer issues on Github and receive Pull Request of any kind.
My next steps for improving these libraries are:
- Remove from beta;
- Refactor the code to a more readable one (
createModule
is a mess I know); - Improve DOCS with more examples;
- 100% test coverage and add more cases;
- Test with Vuex plugin;
- Be referenced into Vuex documentation;