Creating a Global Store in Vue

Posted by Jake Dohm on 15 June, 2019

Creating a global store in Vue

If you have ever worked on a Vue application, a situation has most likely arose where you had some pieces of state that you use in multiple unrelated components. That forces you to decide: Do I put that (global) state in my root Vue instance and pass it all the way down through props, or do I pull in a state management library, like Vuex? Now, you have another option!

When the Vue maintainers released version 2.6, they exposed Vue’s internal reactivity system, the same system used internally for a component’s data. This allows for some pretty cool features, one of which is the ability to create a lightweight, reactive, global store. A big thing to note about that is the word reactive”. Because this state object will be reactive, if you update any piece of state in this store, your Vue app will know about that change and re-render any components that rely on that state, just like it does when you change something in your component’s data.

Let’s walk through how you can create a store and actions to update your state.

Creating a Store

Creating a reactive store is as easy as this:

const store = Vue.observable({ count: 1 })

I really wish there was more to say, but creating a store is so simple!

Creating Actions to Update your State

Let’s talk about actions”: Actions are a way to centralize the way that components are allowed to update state in your store. The actions object is just that: an object containing functions. It doesn’t have any fanciness or magic, it is purely a way for you to dictate how updates to state can be made*.

* There is nothing preventing you from directly mutating a piece of state in the store, the actions pattern is really only for clarity and consistency.

const actions = {
  incrementCount() {
    store.count += 1
  },
  decrementCount() {
    store.count -= 1
  }
}

Making Your Store and Actions Global

The way Vue creates components is practically const component = new Vue(options), which means that anything that you put on the Vue prototype will automatically be inherited by not only the root instance, but every Vue component. So, to make our store global, we can attach it to Vue’s prototype.

Vue.prototype.$store = store
Vue.prototype.$actions = actions

Using Your Store and Actions

Because the store and actions are attached to the Vue prototype, they’ll be automatically available in every component, so you can easily access them in your component.

<!-- Counter Component -->
<template>
  <div>Count: {{ count }}</div>

    <button @click="$actions.incrementCount">+ Add One</button>
  <button @click="$actions.decrementCount">- Subtract One</button>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.count
    }
  }
}
</script>

Complete Example

/* Create a reactive store */
const store = Vue.observable({
  count: ''  
})


/* Create centralized actions for updating the store */
const actions = {
  incrementCount() {
    store.count += 1
  },
  decrementCount() {
    store.count -= 1
  }
}

/*
    Attach store and actions to the Vue prototype
    so they can be accessed from any component
*/
Vue.prototype.$store = store
Vue.prototype.$actions = actions

Conclusion

This might not be the perfect pattern for your application. Sometimes you don’t need a global store. Sometimes you do need a full-fledged state management system like Vuex. But before you pull in a library, or pass props and events up and down through numerous components, it’s worth thinking about whether a simple global store could save you a lot of headache.