To-Do app: Composition API as an alternative to Vuex
After reading an Anthony Gore's article about using the new Composition API as some sort of replacement of Vuex, for smaller projects, I took a simple todo app I built in Codepen, and then I created a new Vue 3 app (using the vue cli) and lastly, I moved all the state and mutation methods from each component to one single file (global.js - which will be something like the store, in Vuex).
Source code and foreword
Here's a list of the source code and the Codepen I will refer to in this article:
Codepen: Vue To-do app
GitHub repo: todo-app-vue3
Netlify: https://relaxed-yonath-fa8475.netlify.app/
If you take a look at the todo app I created in Codepen you'll notice I'm not even using Vuex, I'm just using both props to pass data down to children and $emit to pass data/communicate up to parent components.
One of the advantages of the new Composition API is that now we have access to reactive features outside of components, which is quite powerful.
So here's what I did after creating my Vue 3 app, and putting the components code into its own files, and basically making the app work like it is working on Codepen:
Move the state and mutation functions to a global file
The first thing I did was to create the global.js file in /src
.
Inside global.js
, I imported the reactive
and the readonly
APIs. Let's take a look at the code in 'global.js' - I will add the comments in the code snippet.
import { reactive, readonly } from "vue";
/*
Wrapping our object with reactive() makes,
as it clearly suggests, our object reactive
(it even affects all nested properties).
*/
const state = reactive({
tasks: [
{
id: 1,
description: "Finish the course",
done: false,
},
{..},
{..},
{..},
{..}
],
nextId: 6,
tasksFiltered: [],
activeTab: "all",
})
/*
All these functions below are a combination of
mutations and actions (when comparing with Vuex).
But, of course, we are always free to organize our code
however we want.
*/
const filterTodos = function(filterOption) {..}
const addTodo = function(todo) {..}
const deleteTask = function(task) {..}
const toggleTaskStatus = function(task) {..}
// Export an object with the state and mutations
export default {
// With readonly(), we prevent our state to be mutated
// outside of the global.js module
state: readonly(state),
filterTodos,
addTodo,
deleteTask,
toggleTaskStatus
}
Provide / inject
UseThen, we need to make global.js
(our "custom store") accesible to all of the App.vue
child components. To do so, we have to use the provide
property inside our App.vue
in order to make global.js
available to all the child components, so we import global.js
in App
and then, we provide it.
Right after that, in each component, we need to inject
global
in order to use it on each of them.
Now a screenshot of each child component (but remember, you can always go to the repo and take a look a the code)
TodoList.vue
Form.vue
Header.vue
This approach can be improved, and could serve as a simpler alternative. Of course, Vuex is more debuggable and we can track mutations in the vue dev tools. So it will always depend on the project we're working on or our personal choice and point of view.
What do you think about this approach?
Do you have any suggestions?
Hope you found this article useful! 🙂