Vue: Pinia vs. Vuex


On the one hand, Pinia, the current official state management library for Vue, was developed for Vue 3 and takes advantage of its reactivity system, making it intuitive and simple.
On the other hand, Vuex, the previous official state management library, was developed for Vue 2 and uses the Flux pattern, proposed by Facebook and popularized by Redux.
Many projects were build using Vuex, so it is important to know how it works and how it differs from Pinia.

API & store structure

While Pinia prefers to use separated stores for each kind of data, Vuex uses a single store divided in modules for each kind of data.

Pinia
Store A Store B
Vuex
Store
Module A Module B

While each store of Pinia has a state, getters and actions, each module of Vuex have a state, getters, actions and mutations.

Pinia
Store A
State
Getters
Actions
Store B
State
Getters
Actions
Vuex
Store
Module A
State
Getters
Actions
Mutations
Module B
State
Getters
Actions
Mutations

Let’s see a code example of both.

Creating a store (setup) with Pinia

src/stores/todos.js

import { computed, ref } from 'vue'
import { defineStore } from 'pinia'

export const useTodosStore = defineStore('todos', function() {
  const todos = ref([
    { id: 1, text: 'Learn Vue', done: true },
    { id: 2, text: 'Learn Pinia', done: false },
    { id: 3, text: 'Learn Vuex', done: false }
  ])
  
  const allTodos = computed(function() {
    return todos.value
  })
  
  function doTodo(todoId) {
    todos.value = todos.value.reduce((todos, todo) => {
      if (todo.id === todoId) {
        todo = { ...todo, done: true }
      }
      todos.push(todo)
      return todos
    }, [])
  }

  return { todos, allTodos, doTodo }
})

src/main.js

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

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

Accessing a Getter from the store with Pinia

src/components/TodoList.js

import { storeToRefs } from 'pinia'
import { useTodosStore } from '../stores/todos'

<script setup>
  const { allTodos } = storeToRefs(useTodosStore())
</script>

Accessing an Action from the store with Pinia

src/components/Todo.js

import { useTodosStore } from '../stores/todos'

<script setup>
  const { doTodo } = useTodosStore()
</script>

Creating a store with Vuex

src/store/index.js

import { createStore } from 'vuex'

export default createStore({
  modules: {
    todos: {
      namespaced: true,
      state: {
        todos: [
          { id: 1, text: 'Learn Vue', done: true },
          { id: 2, text: 'Learn Pinia', done: false },
          { id: 3, text: 'Learn Vuex', done: false }
        ],
      },
      getters: {
        allTodos(state) {
          return state.todos
        },
      },
      actions: {
        doTodo(context, todoId) {
          context.commit('doTodo', todoId)
        }
      },
      mutations: {
        doTodo(state, todoId) {
          state.todos = state.todos.reduce((todos, todo) => {
            if (todo.id === todoId) {
              todo = { ...todo, done: true }
            }
            todos.push(todo)
            return todos
          }, [])
        }
      },
    }
  }
})

src/main.js

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

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

Accessing a Getter from the store with Vuex

src/components/TodoList.js

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

<script setup>
const todos = computed(function() {
  return useStore().getters['todos/allTodos']
})
</script>

Accessing an Action from the store with Vuex

src/components/Todo.js

import { useStore } from 'vuex'

<script setup>
function doTodo(todoId) {
  useStore().dispatch('todos/doTodo', todoId)
}
</script>

To learn more about them, we can consult the official documentation of Pinia and Vuex.

Conclusion

Defining and using a store with Pinia is simpler and more intuitive than doing it with Vuex. It also fits better with the reactivity of Vue 3 and the Composition API. Despite that, it is good to know how to work with Vuex because there are a lot of projects that were build with it and we could find ourselves in the situation of maintaining one of those projects.

2024-03-20
Written by Samuel de Vega.
Tags