You may not need vuex. Here are some alternatives
Tags: vue, javascript
Published: 2020-03-23 11:15:46

> Originally posted at [michaelzanggl.com](https://michaelzanggl.com/articles/you-may-not-need-vuex). Subscribe to [my newsletter](https://michaelzanggl.com/) to never miss out on new content.

Let's take a look at two approaches you can take before reaching for vuex!

## First approach (for simpler websites)

Let's consider a typical SPA that is generally separated by page (vue-router) much like a traditional website.

Your application probably has the following three types of state:
1. Local state exclusive to a component
2. Global state that needs to be shared across routes
3. Shared state within a route

The first type of state is very good for, well, local state. Maybe it is exclusive to this component or only goes one or two layers deep.

As for the second type of state, Vue allows you to define data, methods and everything else you might need in the Vue root.

```javascript
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',
  data() {
    return {
      isLoggedIn: false
    }
  }
})
```

Within each component you can then access is via `$root`, e.g. `this.$root.isLoggedIn`.
This is very useful for things like the user instance.

But what about the third type of state? Shared state within a route. Without state management you are probably going to pass down props multiple components deep. And you know what, in many cases, that's just fine! But here's a little trick if you really want to share state within a route.

It turns out Vue actually allows you to access all the state and methods from the route root within any of its subcomponents.

Say the route root exposes the data `{ isOpen: false }`.

Within any subcomponent you can access this property like this:

```javascript
this.$route.matched[0].instances.default.isOpen
```

Okay, that's very very verbose! But it works!

Let me introduce to you a small [plugin](https://github.com/MZanggl/vue-route-root) I wrote that turns the above into:

```javascript
this.$routeRoot.isOpen
```

I haven't actually used this in any projects, but I love its simplicity.

- vuex redefines the way you write state, methods, computed fields, everything really. With this approach, you can leverage your existing knowledge. You still write the state inside "data", you still have your methods, computed fields, literally nothing changes. There is only one paradigm.
- with vuex, all your state is global. Sure you can define modules, but you still manually have to select from which module to get your state even when you are already inside a specific route. When I am on the settings page, I don't care what state was last used on the profile page, etc.

---

There is also a second way you can use this plugin. Instead of registering it, you may map properties from the two roots to your local component if you prefer that.

```javascript
import { mapRoot } from 'vue-route-root'

export default {
  // first one from $root, second and third one one from route root
  computed: mapRoot(['user', 'isOpen', 'setOpen']),
}
```

This has the benefit that you can't just mutate root state from within a child. If you want to mutate state, you need to call a method. This forces you to place all state mutations in the root and makes sure they are not scattered across the application.

**Cautions with this approach**

The vue documentation does not recommend the usage of $root because it "scales poorly". This is very much true if you are not careful. But think about it, $root and $routeRoot are pretty much structure-less. Guess what happens when you are not careful with a very very structured tool like vuex! If you want to change such an implementation, you are required to first destructure it before you can change it.

But I wholeheartedly agree that this approach has its limits.
For example, it forces you to have all logic inside the root components, making them rather big. You also have to be careful to never ever access `$routeRoot` within a dumb/reusable component. It also doesn't allow you everything that vuex does.

## Second approach

Say your application is a little more complex or follows a different approach.

There is another plugin I created which takes more the form of vuex and which doesn't make use of Vue's $root or route roots. I call it [vue-blick](https://github.com/MZanggl/vue-blick).

First, create your store in a simple .js file

```javascript
// store/alert-store.js

import { create } from 'vue-blick'

export default create({
  message: 'Hello', // state

  get reversedMessage() { // computed fields/getters
    return this.message.split('').reverse().join('')
  },

  async setMessage(message) { // methods/actions
    // await fetch(...)
    this.message = message
  }
})
```

And then you can use it in any component like this

```vue
<template>
  <div>alert: {{ message }}</div>
  <div>reversed alert: {{ reversedMessage }}</div>
  <button @click="setMessage('World')">alert!</button>
</template>

<script>
import alertStore from './store/alert-store'

export default {
  mixins: [ alertStore.map('message', 'reversedMessage', 'setMessage') ]
}
</script>
```

What I like about this approach:

- while it is closer to more traditional state management, there are zero terminologies like actions, getters, mutations, reducers, selectors, dispatch, commit, action types, reduce reducers, etc.
- You still access properties within a computed field or method using `this`, exactly the same as in a Vue component
- `mixins: [ userStore.map('message', 'reversedMessage', 'setMessage') ]`: Only one method to map state, getters and methods. And you map it in one place only... **Without any destructuring!**

---

Just like the vuex documentation states: You should weigh the trade-offs and make decisions that fit the development needs of your app. Maybe instead, you can let the server hold such state, like with [inertia.js](https://inertiajs.com/). Or Maybe vuex is exactly what you need!

---

If this article helped you, I have a lot more tips on simplifying writing software [here](https://michaelzanggl.gumroad.com/l/intent-driven-development).