Do you need Vuex?
Tags: vue, typescript, javascript
Published: 2020-04-01 23:43:36

With the upcoming release of Vue 3 and its much anticipated composition API, I took some time to read up on it ahead of time. I recommend reading [Composition API RFC](https://vue-composition-api-rfc.netlify.com/) it covers everything about the API. Vue allowing us direct access to it's reactivity is very useful. One use for this could be to get rid of Vuex 😁

## What's wrong with Vuex?
_OK time for some random dude on the internet's opinion._ Vuex is great for sharing state between components when the normal method for sharing data via props becomes cumbersome. But more often than not Vuex becomes a dumping ground for all data related to an applications state or data which doesn't need to be reactive. I don't think this would be so bad if there wasn't so much overhead for access/modifying data. Create a `mutation`, don't forget the `getter`! Oh wait that's async! Create an `action` to call the `mutation` 😅.

Probably the final nail on the coffin for me is around `Typescript`. I have yet to find a _nice_ solution to interacting with Vuex, especially given it's reliance on strings for `mutation` and `action` names.

## Vuex Example

Let's start with a simple example of a Vuex store.

```ts
import { Article } from "../models";
import { ActionContext } from "vuex";
import api from "../api";
import Vue from "vue";
interface ArticleState {
  articles: Article[];
}
const articleModule = {
  namespaced: true,
  state: {
    articles: []
  },
  mutations: {
    setArticles(state: ArticleState, arr: Article[]) {
      state.articles = arr;
    },
    updateArticle(state: ArticleState, a: Article) {
      const index = state.articles.findIndex(v => v.id === a.id);
      if (index > -1) {
        Vue.set(state.articles, index, a);
      }
    }
  },
  actions: {
    loadArticles(context: ActionContext<ArticleState, unknown>) {
      api.load().then(res => context.commit("setArticles", res));
    },
    like(context: ActionContext<ArticleState, unknown>, a: Article) {
      api.like(a).then(res => context.commit("updateArticle", res));
    }
  },
  getters: {
    articles(state: ArticleState) {
      return state.articles;
    },
    totalLikes(state: ArticleState) {
      return state.articles.reduce((p, c) => p + c.likes, 0);
    }
  }
};
export default articleModule;
```

That's a lot of code for exposing `articles`, `totalLikes` and providing a mechanism to `loadArticles` and `like` a given article. Also has magic strings in there for committing the mutations, which I know could be extracted out to constants but yet again that's more code for a relatively simple module.

## Composition API

I wanted to try and recreate this store like functionality using the new Vue composition API. Here is what I have come up with:

```ts
import { ref, computed } from "@vue/composition-api";
import { Article } from "../models";
import api from "../api";

const _articles = ref([] as Article[]);

const loadArticles = () =>
  api.load().then(articles => {
    _articles.value = articles;
  });

const like = (incoming: Article) =>
  api.like(incoming).then(res => {
    const index = _articles.value.findIndex(a => a.id === res.id);
    _articles.value.splice(index, 1, res);
  });

export default {
  articles: computed(() => _articles.value),
  totalLikes: computed(() => _articles.value.reduce((p, c) => p + c.likes, 0)),
  loadArticles,
  like
};
```

Here I expose methods to act upon hidden reactive data. I then expose this reactive data via `computed` functions so that they are readonly. NOTE: The documentation for the API states there should be a [readonly](https://vue-composition-api-rfc.netlify.com/api.html#readonly) but I was unable to find a way to import it. `Computed` offers a similar readonly functionality.

### Benefits

Here are some of the benefits I see:
 - I may be biased (read I am) but I find the composition API version a lot nicer to read and follow. 
 - There is no magic strings I have to worry about.
 - Typing is obvious and less complex than having to worry about typing the overall `state`.
 - There are no scenarios where you have to use the Vue.set.
 - There is no pollution of the Vue prototype. This is particularly important as it means it is easier to track where this solution is being used and that we can easily tree shake/code split our solution with out having to dynamically register anything.

## Pinch of salt

I have not seen the next version of Vuex that utilizes the latest composition API functionality so it may well address some of the short comings I see with it currently.  With that being said, I am still not sure I will use it given I can achieve the same results with the standard composition API. 

I would love to know your thoughts on using Vuex when Vue 3 is released?