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:
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, for this we need to run:
npm init @vitejs/app storex (or the name you want to use)
After that, select vue
Then JavaScript or TypeScript, it will work in both:
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:
Once created the index file open it and place the next code:
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:
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
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:
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:
<script setup>
import { computed } from '@vue/runtime-core'
import HelloWorld from './components/HelloWorld.vue'
import store from './store'
const state = computed(() => store.state)
</script>
In case you want to make only the state visible you need to change the code like this but always using the Composition API:
<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>
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:
<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!
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 or 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.
Top comments (2)
Thanks you!
This was very helpful!
how to do this in type script