The Composition API has freed reactive data from Vue components and instances, allowing it to be passed around like any JavaScript object. This has an obvious application - global reactive state. If this can be achieved, what do you need Vuex for?
In this article, I'll show you how you can replace Vuex with features of the Composition API, and also make the case for whether this is a wise idea or not.
Note: this article was originally posted here on the Vue.js Developers blog on 2020/10/04.
If you want to brush up on the concepts of Vuex, first read WTF is Vuex? A Beginner's Guide To Vue's Application Data Store. And if you aren't familiar with the Vue Composition API, you can learn about that here.
Global reactive state with Composition API
The main reason Vuex exists is to allow global reactive state in a Vue app. Without it, you could only share local component state via the component interface i.e. props/events. Passing props and events from a component four of five layers deep is a type of drudgery all too familiar to Vue users.
However, the Composition API (packaged with Vue 3) allows you to create independent reactive variables outside of a component (and, in fact, outside of a Vue app). You can, for example, create a module file exporting reactive variables and import this into any component where you want to use it.
DIY Vuex with Composition API
Let's see how we can roll our own Vuex using the Composition API. Firstly, we'll create a file to declare and export global state variables.
Let's use the reactive
method to create a state object with a value count
, assuming we want to use this count value throughout the app.
src/global.js
import { reactive } from "vue";
const state = reactive({
count: 0
});
export default { state };
Vuex pattern
As the Vuex documentation says - Vuex is both a pattern and a library. To make state predictable, it's important that variables aren't directly mutated.
We can implement that easily enough in our DIY Vuex. We'll use the readonly
method which creates a read-only copy of our state. We'll also provide a method increment
which is what users will use to change the value of count (this is akin to a Vuex mutation).
src/global.js
import { reactive, readonly } from "vue";
const state = reactive({
count: 0
});
const increment = function () {
state.count++;
}
export default { state: readonly(state), increment };
Installing the store with provide/inject
The easiest way to use our DIY Vuex store is with the provide/inject feature. So we'll import this module in the app's root instance, then provide
it so it's available to all child components.
src/main.js
import { createApp } from "vue";
import global from "@/global";
const app = createApp({
provide: {
global
},
...
}
Now, we can access it by using inject
:
src/components/MyComponent.vue
<template></template>
<script>
export default {
inject: ["global"]
}
</script>
The states values and methods can be used now:
src/components/MyComponent.vue
<template>
<div>{{ global.state.count }}
<button @click="global.increment">Increment</button>
</template>
<script>
export default {
inject: ["global"]
}
</script>
So should you ditch Vuex?
We've seen how we can roll our own Vuex using Composition API. In doing so, we've overcome a lot of the complaints about Vuex because we have:
- Minimal boilerplate
- No esoteric naming like "mutations", "commits", etc
- No additional dependencies.
So why not ditch Vuex altogether?
Advantage of Vuex 1: debugging
Even though we've copied the global reactive state mechanism, one huge advantage of Vuex that we have not copied is it's debugging capabilities.
Firstly, all mutations are tracked with Vuex, allowing you to see in Vue Devtools what component changed the state and how.
Secondly, there's time-travel debugging. This is a feature of Vuex where you can select any previous state of the app.
Advantage of Vuex 2: plugins
Another advantage of Vuex is the plugin ecosystem. For example, the vuex-persisted state plugin allows you to persist app state in local storage, and the Vue Router plugin which syncs the current route data in store state.
All the existing plugins could indeed be replicated as Composition API utilities, but without the standardized structure of Vuex, they wouldn't be plug and play.
Conclusion
There's no harm in creating a simple module for global reactive state using Composition API in a small project, or if it's really important to avoid any overhead.
But the debugging capabilities of Vuex still make it an essential tool for large-scale Vue app development and I can't imagine I'd stop using it in this case.
Looking forward to what's next for Vuex in version 5.
Further reading
- Do React Hooks Replace Redux?
- How to Use the Vue 3 Composition API for Global State Management (without Vuex)
Enjoy this article?
Get more articles like this in your inbox weekly with the Vue.js Developers Newsletter.
Top comments (0)