Introduction
Vue 3 has become the default version of Vue and it seems that its ecosystem has undergone a revolution. Before, the recommended tools to work with were Vetur, Vue CLI and Vuex; now they are Volar, Vite and, the one that interests us in this article; Pinia.
Pinia is not new, it has been under development for some time, but it has been with the publication of the final version of Vue 3 when it seems to be gaining popularity, especially if we take into account that Evan You (creator of Vue) is the one who recommends its use instead of Vuex. What’s more, for him, Pinia would be Vuex 5, a declaration of intent.
So, what makes Pinia special and why should you consider it as an alternative to Vuex for your projects? I’m going to try to tell you in a simple way in this article.
What is Pinia?
Pinia is a new state management library for the Vue ecosystem, developed by Eduardo San Martin, member of the Vue Core team and also known for developing the essential Vue Router. As a state manager, it fulfils the same function as Vuex and many other libraries with the same purpose, although in this case, Pinia would be official and has the support of the team in charge of Vue.
At this point you may be wondering what’s going on with Vuex. Well, actually, it will continue to be supported and is still one of the official recommendations, so you shouldn’t worry about it. However, considering that it aims to be the replacement for Vuex, it is not a bad option for projects using version 3 of Vue to start getting familiar with Pinia. Especially considering the advantages it offers, which we are going to see below.
What’s New?
Goodbye to mutations
If there’s one thing that gets tiresome when working with Vuex, it’s the use of mutations. To modify the state of our store from a component we first call an action and this calls a mutation that will modify the state. In the end, this means that each change of state requires a lot of boilerplates, that is to say, a lot of repeated code.
Let’s see how a simple store would look like in Vuex:
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
items: []
}
},
actions: {
addItem({ commit }, item) {
commit('addNewItem', item)
}
},
mutations: {
addNewItem(state, item) {
state.items.push(item)
}
}
})
This is how it would look with Pinia:
import { defineStore } from 'pinia'
Export const useCartStore = defineStore('cart', {
state() => ({
return {
items: []
}
}),
actions: {
addItem(item) {
this.items.push(item)
}
}
})
If such a simple example shows a clear improvement of our code, it is not difficult to imagine how it will work in a real project.
No dispatch or mapAction
Continuing with the previous store example, to call from a component to the action ‘addItem’ we could find something like this:
<template>
// …
<button @click=”addItem('apple')”>Apple</button>
</template>
<script>
import { mapActions } from 'vuex'
// …
methods: {
…mapActions([
'addItem'
])
}
</script>
It’s something we’re used to working with, but we must admit that at first glance the idea of using an array of strings that refer to the methods defined in the store is already creaky.
Let’s see how it would look in Pinia:
<template>
// …
<button @click=”cart.addItem('apple')”>Apple</button>
</template>
<script>
import { useCartStore } from './stores/cart'
// …
const cart = useCartStore()
</script>
In this case, the action is called as if it were a normal JavaScript function. Also, you may have noticed that we are directly importing the store we have created, which gives us a clue that we can work with different stores, which links to the next point.
Different stores
In Vuex we can’t have different stores. Yes, it is true that we can divide it into different modules, but this is quite cumbersome, especially when we import a module into our component:
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
}),
...mapGetters([
'some/nested/module/someGetter',
'some/nested/module/someOtherGetter',
])
},
On the contrary, in Pinia we work with different stores and we import those that we are going to need in our component, being able to be one or several. In addition, accessing them is much simpler and cleaner because it is not the same to call a JavaScript function than using a string to call a method, with the problems that this entails.
DevTools Support
One of the advantages of Pinia receiving official support from the Vue Core is that, as with Vuex, we will also have support for all the development tools that we already have in Vuex. Working with the tools we are used to in our browser or IDE will continue to be just as comfortable with Pinia, so the migration from one library to another should be quite transparent in this aspect.
TypeScript Support
Another point to keep in mind is that Pinia has TypeScript support unlike Vuex, which is arguably not very TypeScript friendly. You may wonder what advantage this has if you don’t use TypeScript. It’s simple: when a library supports TypeScript, it makes our code tools easier to use with automatic suggestions.
In addition, the way we write code encourages better practices. We’ve seen before that we don’t access mutations as a string, as we did with Vuex, but as normal JavaScript functions:
// Vuex
commit('increment')
// Pinia
this.increment()
Conclusion
Should I upgrade my project using Vuex to Pinia? This is something quite personal but I, honestly, for an application that is in production and is developed in Vue 2 with Vuex, I would not rush to implement the new library. For a project that is not going to receive new features but is mainly in maintenance, I don’t think the advantages of Pinia can compensate the cost of a migration.
In the case of a project with a long development phase ahead or that is not in its final stages, it could be quite interesting to consider migrating from Vuex to Pinia.
However, if it is a new project, it would definitely be my option of choice because of all the advantages it offers. For someone who is familiar with Vuex, it is not going to be a steep learning curve. What’s more, I think it will save a lot of headaches. Add to this the fact that TypeScript is going to be used, and I would say that Pinia is almost a must.
Interesting Links
Pinia official website: https://pinia.vuejs.org/