Vuex: why we don’t need it

Tomas Bjerre
3 min readMar 18, 2021

--

I asked myself: Why do I need Vuex? I did not find a good answer. Here is why I question the value of Vuex.

I found this article:
https://blog.logrocket.com/vuex-why-we-need-spa-state-management/

Which does not really answer, why? It explains what Vuex does, but why can you not do that with a simple service?

I forked that repo and re-wrote it without Vuex and with an ApplicationService that takes care of state management.

Code comparison

Here are the interesting code to compare between:

The state

The Vuex code is here:
https://github.com/malgamves/vuex-remindrr-app/blob/master/src/store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
state: {
username: "danielphiri",
tasks: [
{ taskName: "take pictures", taskReciever: "mom and dad" },
{ taskName: "email organisers slides", taskReciever: "myself" },
{ taskName: "send resume", taskReciever: "dev job" },
]
},
getters: {
taskCount: state => {
return state.tasks.length;
}
},
mutations: {
ADD_TASK: (state, task) => {

state.tasks.push(task);
},
REMOVE_TASK: (state, task) => {
state.tasks.splice(task, 1);
},
REMOVE_ALL: state => {
state.tasks = [];
}
},
actions: {
removeTask: (context, task) => {
context.commit("REMOVE_TASK", task);
},
removeAll({ commit }) {
return new Promise((resolve) => {
setTimeout(() => {
commit("REMOVE_ALL");
resolve();
}, 2000);
});
}
}
});

My service code is here:
https://github.com/tomasbjerre/not-vuex-remindrr-app/blob/master/src/services/ApplicationService.ts

export interface TodoTask {
taskName: string;
taskReciever: string;
}

export interface MainModel {
username: string;
}

export interface ApplicationState {
mainModel: MainModel;
tasks: TodoTask[];
}

export class ApplicationService {
private state: ApplicationState = {
mainModel: {
username: "tomasbjerre",
},
tasks: [
{ taskName: "take pictures", taskReciever: "mom and dad" },
{ taskName: "email organisers slides", taskReciever: "myself" },
{ taskName: "send resume", taskReciever: "dev job" },
],
};

public getMainModel(): MainModel {
return this.state.mainModel;
}

public getTasks(): TodoTask[] {
return this.state.tasks;
}

public addTask(taskName: string, taskReciever: string): void {
this.state.tasks.push({ taskName, taskReciever });
}

public removeTask(taskIndex: number): void {
this.state.tasks.splice(taskIndex, 1);
}

public removeAllTasks(): void {
this.state.tasks.splice(0, this.state.tasks.length);
}
}

export default new ApplicationService();

Usage in Main.vue

The Vuex code is used here:
https://github.com/malgamves/vuex-remindrr-app/blob/master/src/components/Main.vue

<script>
import { mapState, mapMutations, mapActions } from "vuex";

export default {
name: "Main",
data() {
return {
taskName: "",
taskReciever: "",
};
},
computed: {
...mapState(["tasks", "username"])
},
methods: {
...mapMutations(["ADD_TASK"]),
...mapActions(["removeTask"]),
addTask: function() {
let newTask = Object.create(null);
newTask["taskName"] = this.taskName;
newTask["taskReciever"] = this.taskReciever;
this.ADD_TASK(newTask);
this.taskReciever = "";
this.taskName = "";
},
removeTasks: function(task) {
this.removeTask(task);
}
}
};
</script>

My service code is here:
https://github.com/tomasbjerre/not-vuex-remindrr-app/blob/master/src/components/Main.vue

<script lang="ts">
import { ApplicationService } from "@/services";
import Vue from "vue";

export default Vue.extend({
name: "Main",
data() {
return {
taskName: "",
taskReciever: "",
mainModel: ApplicationService.getMainModel(),
tasks: ApplicationService.getTasks(),
};
},
methods: {
addTask: function () {
ApplicationService.addTask(this.taskName, this.taskReciever);
},
removeTasks: function (taskIndex: number) {
ApplicationService.removeTask(taskIndex);
},
},
});
</script>

Usage in Stats.vue

The Vuex code is used here:
https://github.com/malgamves/vuex-remindrr-app/blob/master/src/components/Stats.vue

<script>
import { mapGetters, mapActions, mapMutations, mapState } from 'vuex'

export default {
name: 'Stats',
computed: {
...mapGetters(['taskCount']),
...mapState(["username"])
},
data() {
return {
message: ""
}
},
methods: {
...mapMutations(['REMOVE_ALL']),
...mapActions(['removeAll']),
removeAllTasks() {
this.removeAll().then(() => {
this.message = 'Self care - tasks are gone'
});
}
}
}
</script>

My service code is here:
https://github.com/tomasbjerre/not-vuex-remindrr-app/blob/master/src/components/Main.vue

<script>
import { ApplicationService } from "@/services";

import Vue from "vue";
export default Vue.extend({
name: "Stats",
data() {
return {
message: "",
mainModel: ApplicationService.getMainModel(),
tasks: ApplicationService.getTasks(),
};
},
methods: {
removeAllTasks() {
ApplicationService.removeAllTasks();
this.message = "Self care - tasks are gone";
},
},
});
</script>

Conclusions

Vuex is something you need to understand. That is true, regardless of how complicated Vuex is. Explicit method calls, that I use in my service, is something most developers are familiar with, you don’t even need to be a frontend developer to understand it.

You do not need Vuex to hold your global application state. I have shown that you can do that in a singelton service.

You do not need Vuex to get reactivity. You can achieve that by returning objects from the service, and mutate (not replace) those objects when working with your state.

One problem with my service is that the objects returned from the service can be mutated by the components. With Vuex you can avoid that. But if you do not need reactivity, you can just return a copy from the service and it is solved.

--

--

Responses (18)