Learn to create your custom Global State Management with Vue 3
Tags: vue, vue3, javascript
Published: 2021-05-10 19:46:09

# Learn to create your custom Global State Management with Vue 3

Since Vue 3 Beta days we knew how awesome this framework was going to be, and since it annoucement we knew they did a monorepo making a lot of the feature from the framework available outside a **Vue** component, with this I mean:

```js
import { /* Anything you need from Vue goes here */ } from 'vue'
```

So we are going to use this advantage to create a simple but powerful Global State Management with a single few steps, so let's get started.

---

## Let's create a simple app

For this example let use a simple example, a counter that comes for default using the amazing [Vite.js](https://vitejs.dev/), for this we need to run:

```console
npm init @vitejs/app storex (or the name you want to use)
```

After that, select **vue**

![Select Vue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3kqvncm3p2ofvt81iml6.png)

Then **JavaScript** or **TypeScript**, it will work in both:

![Select JS or TS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5s7vu6bb2xmo1tskzvuo.png)

Then follow the rest by changing into the recently created project and run **npm install** and open up the code in the the editor of your preference.

---

## Creating the store

Let's begin with the store by creating a new folder inside the **src** folder by naming it, as you probably guess it, **store** and create a **index.js** inside the folder, the project directories should look like somethimg like this:

![Creating the store directory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xvp2hd6gso4zmmz0a4lh.png)

Once created the index file open it and place the next code:

```js
import { reactive } from 'vue'

const store = ({
  state: reactive({
    count: null
  }),
  getters: {
    getCount() {
      return store.state.count
    }
  },
  mutations: {
    incrementCount() {
      store.state.count++
    }
  },
  actions: {
    initializeCount() {
      store.state.count = 0
    }
  }
})

export default store
```

Let explain why the store is created like this:

```js
import { reactive } from 'vue'

// We need to import the reactive function from Vue to make the
// global object reactive and get the treatment like this was Vuex
```

```js
const store = ({
  // Create a state with the reactive function we imported previously, this will manage the reactivity for us
  state: reactive({
    count: null 
    // If this is null is for the example,
    // of course you can initialize the
    // counter with 0 directly
  }),
  // This section will handle the getters
  getters: {
    getCount() {
      return store.state.count
    }
  },
  // This section will manage the changes into the state
  mutations: {
    incrementCount() {
      store.state.count++
    }
  },
  // This section will manage the actions needed for our store
  actions: {
    initializeCount() {
      store.state.count = 0
    }
  }
})
```

And that's it, the store is created, now we need to use it in our app.

---

## Using the Store in the App

Open **main.js** file in the root of **src** and change the code with this:

```js
import { createApp } from 'vue'
import store from './store'
import App from './App.vue'

const app = createApp(App)
store.actions.initializeCount()

app.mount('#app')

/*
* By default the main.js comes like this:
* createApp(app)
* .mount(#app)
* We changed a little the behaviour by assigning the createApp 
* to the const app to avoid the mount before initializing the store
*/
```

In **App.js** we need to change or add the store to track correctly in a global way when we are debugging/testing the application, so let's add the **state** as a computed property:


### **App.vue**

If you want to use this sugar syntax, this all what you need, but be aware that the complete store is visible in the Dev Tools:
```html
<script setup>
import { computed } from '@vue/runtime-core'
import HelloWorld from './components/HelloWorld.vue'
import store from './store'

const state = computed(() => store.state)
</script>
```

![The store is visible in the Dev Tools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gr2t7ze4og6nwuj502d6.png)
*<center>As mentioned the store is completily visible in the dev tools</center>*

In case you want to make only the state visible you need to change the code like this but always using the Composition API:

```html
<script>
import { defineComponent, computed } from '@vue/runtime-core'
import HelloWorld from './components/HelloWorld.vue'
import store from './store'

export default defineComponent({
  components: {
    HelloWorld
  },
  setup () {
    const state = computed(() => store.state)

    return {
      state
    }
  }
})
</script>
```

![State only visible in the dev tools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yvlb1oa3r71o8vvc6ad.png)
*<center>Only the state is visible in dev tools, so this is easily to debug when is needed</center>*


### **HelloWorld.vue**

Open up **HelloWorld.vue** which can be found in the **Components** directory.

Once is ready to edit you need to change the code for this:

```html
<template>
  <h1>{{ msg }}</h1>

  <p>
    <a href="https://vitejs.dev/guide/features.html" target="_blank">
      Vite Documentation
    </a>
    |
    <a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
  </p>

  <!-- 
    You need to change the @click for the method created that
    will handle the change from the store
    Also change the count inside the {{  }}
  -->
  <button @click="increment">count is: {{ count }}</button>
  <p>
    Edit
    <code>components/HelloWorld.vue</code> to test hot module replacement.
  </p>
</template>

<!-- 
  Change the script from the sugar syntax 
  to the Oficial Composition API way
-->
<script>
import { defineComponent, computed } from 'vue'

// Import the store
import store from '../store'

export default defineComponent({
  props: {
    msg: String
  },
  setup () {
    // Send the count as a computed value from
    // the getters in the store
    const count = computed(() => store.getters.getCount())
    
    // This method will commit the change from the store
    const increment = () => {
      store.mutations.incrementCount()
    }

    return {
      count,
      increment
    }
  }
})
</script>

<style scoped>
a {
  color: #42b983;
}
</style>
```

And we get this final result!

![Our app is working](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvexy27ucd4dwbmztjka.gif)

And that's it!!! We have created a simple but powerful Global State Management using the tools that Vue gives us and is fantastic what we can create from it, of course if you need advanced features I recommend to use [Pinia](https://github.com/posva/pinia) or [Vuex](https://github.com/vuejs/vuex), but if you don't want to add more weight into your project this simple State Management should be enough.


Tell me what you think of this trick in the commentary and I hope is helpful for you, see around the next time.

![See you soon](https://media1.tenor.com/images/88ae11548eb77b751325c3ff493cddcc/tenor.gif)