DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Vuex β€” solving old problems with new methods
Eugene Petryankin
Eugene Petryankin

Posted on

Vuex β€” solving old problems with new methods

This is a translation of my Russian article.

Vuex has one popular practiceβ€Š-β€Šnot to use mapState and mapMutations. At all. Instead, we just immediately get a getter for every new value in the store and an action for every mutation.

Something like:

export default new Vuex.Store({
   state: {
      // 1
      count: 0
   },
   getters: {
      // 1
      count: (state) => state.count
     },   
   mutations: {
      // 2
      increment(state) {
         state.count++;
      }
   },
   actions: {
      // 2
      increment({ commit }) {
         commit('increment');
      }
   }
});

Let me prove to you why it is necessary to write a getter for each value in the state and an action for each mutation.

There are two reasons. First: we simplify components and remove confusion.

import { 
   mapState, 
   mapGetters, 
   mapMutations, 
   mapActions 
} from 'vuex';
export default {
   computed: {
      ...mapState(['count']),
      ...mapGetters(['text'])
   },
   methods: {
      ...mapMutations(['increment']),
      ...mapActions(['fetch'])
   }
};

What if this component would have been many times larger. How will you determine which store methods are mutations and whichβ€Š-β€Šactions? Would you constantly look in store.js to check? Maybe write it on a piece of paper?Β :)

You could come up with a naming convention, e.g. incrementMutation, decrementAction. This solves this problem. But now, in addition to using two methods instead of one, we also have super long names. Not to mention the fact that in <template> they look awful.

It is much more convenient to immediately determine getters for all values ​​from the state, and actions for all mutations. And call only them in the components.

There is also a second reason, more conceptual.

What is the first principle that any programmer is learning? DRY. Don't repeat yourself. Why? Because if you have to change something, you have to do it in a bunch of places, and the larger the application, the more difficult it is to make any change.

The fact that when changing the value from state to getter or mutation to action, we have to go through all the components and change themβ€Š-β€Šthis is an accurate definition of the DRY principle violation. And it would be nice if it was not there.

In short, there are enough reasons for our decision.

However, there is one "small" problemβ€Š-β€Šour store now looks like a dump, where each new value doubles the amount of code at best.

What can we do about it? Not much.

We can:

  1. accept it;
  2. use modules to hide the problem;
  3. abandon vuex in favor of another way of storing data (the Composition API, for example, already has an interesting solution) and already deal with problems of other libraries.

I have a fourth solution. I created an addon named vuex-map. It provides you with two new methods mapData and mapMethods (names are still being discussed).

mapData replaces the functionality of mapState and mapGetters. You write

mapData(["count"])

If there is such getter, vuex calls it, if not, it looks for such value in the state.

Similarly, mapMethods returns an action, and if there is no such action, it commits a mutation with that name.

This is actually a very simple idea. It is surprising that vuex developers did not add it to the core library. It takes only 100 lines of code and it solves all of the above problems.

You do not care if there is a getter for a property or not. If there is, then it will be called, if not, you just get the value. In any case, you write mapData. Same with mutations and actions and mapMethods.

And you do not have extra getters like count: state => state.count, etc.

What about DRY? Everything is OK. If you need a getter or action, you just add it, you do not need to change anything in the components. New getters and actions simply obscure values and mutations with the same name.

The addon is ready to use. All tests are written, will add types soon.

Here is a link to the repository on Github

I suggest everyone try and evaluate. I would be grateful for any feedback and any contribution. Thanks.

Top comments (0)

Every Week

We have a Welcome Thread where we invite members to tell us a bit about themselves. Join the conversation with us!