This in Vuex class modules
Vuex module decorators allow Vuex module code to be written in the form of a class, rather than in a structured object that follows a specific convention. However, the abstraction is incomplete and even in the class you must follow some conventions or your code will break at runtime.
Here is a simple example of a Vuex module class, taken from the official documentation:
import { Action, Module, Mutation, VuexModule } from "vuex-module-decorators";
import { get } from "~/services/request";
@Module({ name: "vehicle", stateFactory: true, namespaced: true })
export default class VehicleModule extends VuexModule {
wheels: number = 2;
get axles(): number {
return this.wheels / 2;
}
@Mutation
puncture(n: number): void {
this.wheels = this.wheels - n;
}
@Mutation
addWheel(n: number) {
this.wheels = this.wheels + n;
}
@Action({ rawError: true })
async fetchNewWheels(wheelStore: string): Promise<void> {
const wheels = await get(wheelStore);
this.addWheel(wheels);
}
}
It shows the four basic Vuex concepts and how they are represented in a module class:
- Regular properties become Vuex state.
- Property getters become Vuex getters.
- Methods with the
@Mutation
decorator become Vuex mutations. - Methods with the
@Action
decorator become Vuex actions.
These are also the only types of class members supported. If you try to add an undecorated method, you will run into problems. Let us say I want to add a helper method to be called by an action:
@Action({ rawError: true })
async fetchNewWheels(wheelStore: string): Promise<void> {
if (!this.validate(wheelStore)) {
return
}
const wheels = await get(wheelStore)
this.addWheel(wheels)
}
validate(_wheelStore: string): boolean {
return true
}
Although the code compiles without any problems, it fails at runtime with the following error:
this.validate
is not a function
This happens because the action methods in the module class are called with a rebound this
value, as documented:
Once decorated with
@Action
the function will be called withthis
having the following shape -{...[all fields of state], context}
.
The rebound this
value will actually contain more than what is listed above, namely all the standard Vuex members (fields of state, getters, mutations and actions), along with the Vuex context and store objects. However, all other class members (such as the validate
method above) will not be included and therefore will not be accessible:
In mutation methods, the rebound this
value is even more limited. It only contains the Vuex fields of state:
Despite all this, there is a way to reuse some of the code from multiple actions. It only has to be placed in a function outside the class:
function validate(_wheelStore: string): boolean {
return true
}
@Module({ name: 'vehicle', stateFactory: true, namespaced: true })
export default class VehicleModule extends VuexModule {
{
// ...
@Action({ rawError: true })
async fetchNewWheels(wheelStore: string): Promise<void> {
if (!validate(wheelStore)) {
return
}
const wheels = await get(wheelStore)
this.addWheel(wheels)
}
}
If you need access to state in this function, you must pass it as a function parameter.
You can find a sample Nuxt application that demonstrates the above behavior in my GitHub repository.
Although the Vuex module decorators give the illusion that the Vuex module code is encapsulated in a class, it is still limited to only the standard Vuex concepts: state, getters, mutations, and actions. All other members of the class are inaccessible at runtime. However, Vuex module decorators still provide a lot of value with type-safe access in TypeScript.