Vuex 4 in Vuejs 3, with the composition api

Too long to read: yes, you can use vuex 4 with the composition api. Hints on how to do this are, at present, hidden in git repo’s and discord channels, so I thought I’d share the secret here.

I used the code from github.com/vuejs/vuex/tree/4.0/examples/composition/counter as my starting point.

A template file could look like the below. I bolded the essential parts:

<template>
<div id="app">
Clicked: {{ count }} times, count is {{ evenOrOdd }}.
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">Increment if odd</button>
<button @click="incrementAsync">Increment async</button>
</div>
</template>

<script>
import { computed } from 'vue'
import { useStore, } from 'vuex'

export default {
name: 'counter',
setup () {
 const store = useStore();
  return {
   count: computed(() => store.state.count),
   evenOrOdd: computed(() => store.getters.evenOrOdd),
   increment: () => store.dispatch('increment'),
   decrement: () => store.dispatch('decrement'),
   incrementIfOdd: () => store.dispatch('incrementIfOdd'),
   incrementAsync: () => store.dispatch('incrementAsync')
  }
}}
</script>

That’s really the most difficult part 😁. But to complete the example, here’s how to include vuex in your main.js:

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

createApp(App)
.use(store)
.mount('#app')

And here’s how a sample store could look:

import { createStore } from 'vuex'

// root state object.
// each Vuex instance is just a single state tree.
const state = {
count: 0
}

// mutations are operations that actually mutate the state.
// each mutation handler gets the entire state tree as the
// first argument, followed by additional payload arguments.
// mutations must be synchronous and can be recorded by plugins
// for debugging purposes.
const mutations = {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}

// actions are functions that cause side effects and can involve
// asynchronous operations.
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement'),
incrementIfOdd ({ commit, state }) {
if ((state.count + 1) % 2 === 0) {
commit('increment')
}
},
incrementAsync ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('increment')
resolve()
}, 1000)
})
}
}

// getters are functions.
const getters = {
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
}

// A Vuex instance is created by combining the state, mutations, actions,
// and getters.
export default createStore({
state,
getters,
actions,
mutations
})

So far this post is nothing more than a search engine friendly way to share that git-repo. So thanks to kiaking as usual.

However, there is not much reason to do it this way, unless you want to extract some commonly used code into the composition api.

Say we want to use our timer in different places in our app, we could do it in two ways:

  1. We could move all the logic into vuex and use it directly in each place where we’re using the counter.
  2. We could create a composable – a javascript file that uses the composition api – in which we put our logic.

Personally I’m not quite sure yet which of these two routes I prefer.

However, the topic of this post is the composition API, I’ll follow the second route here:

//myComposable.js

import {computed} from "vue";
import {useStore} from 'vuex';

export const myComposable => {
 const store = useStore();
  return {
   count: computed(() => store.state.count),
   evenOrOdd: computed(() => store.getters.evenOrOdd),
   increment: () => store.dispatch('increment'),
   decrement: () => store.dispatch('decrement'),
   incrementIfOdd: () => store.dispatch('incrementIfOdd'),
   incrementAsync: () => store.dispatch('incrementAsync')
  }
}

To use the above in a component our setup method changes to the following:

<script>
import { computed } from 'vue'
import { myComposable } from '@/myComposable.js'

export default {
name: 'counter',
setup () {
  const {
   count,
   evenOrOdd,
   increment,
   decrement,
   incrementIfOdd,
   incrementAsync
  } = myComposable;
  return {
   count,
   evenOrOdd,
   increment,
   decrement,
   incrementIfOdd,
   incrementAsync
  }
}}
</script>

Now you can reuse the computed properties & methods from myComposable.js in any template file you like.

Geef een reactie

Deze site gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.