Vuex Module Decorators
Vuex Module Decorators
Package that allows you to seamlessly use TypeScript and Decorators with Vuex.
yarn add vuex-module-decorators...and for projects still on vue-cli 2
yarn add --dev babel-plugin-transform-decorators.babelrc
{
"plugins": ["transform-decorators"]
}Modules
// eg. /app/store/modules/mymodule.ts
import { Module, VuexModule } from 'vuex-module-decorators'
@Module
export default class MyModule extends VuexModule {
someField: string = 'somedata'
}import Vuex from 'vuex'
import MyModule from '~/store/mymodule'
const store = new Vuex.Store({
modules: {
myMod: MyModule
}
})Module
Store
State
import { Module, VuexModule } from 'vuex-module-decorators'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
}export default {
state: {
wheels: 2
}
}Becomes:
Getters
import { Module, VuexModule } from 'vuex-module-decorators'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
get axles() {
return wheels / 2
}
}export default {
state: {
wheels: 2
},
getters: {
axles: (state) => state.wheels / 2
}
}Becomes:
Mutations
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
@Mutation
puncture(n: number) {
this.wheels = this.wheels - n
}
}export default {
state: {
wheels: 2
},
mutations: {
puncture: (state, payload) => {
state.wheels = state.wheels - payload
}
}
}Becomes:
Actions
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
import { get } from 'request'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
@Mutation
addWheel(n: number) {
this.wheels = this.wheels + n
}
@Action
async fetchNewWheels(wheelStore: string) {
const wheels = await get(wheelStore)
this.context.commit('addWheel', wheels)
}
}Actions
const request = require('request')
export default {
state: {
wheels: 2
},
mutations: {
addWheel: (state, payload) => {
state.wheels = state.wheels + payload
}
},
actions: {
fetchNewWheels: async (context, payload) => {
const wheels = await request.get(payload)
context.commit('addWheel', wheels)
}
}
}Becomes:
Alternative Syntax
@Mutation
updatePosts(posts: PostEntity[]) {
this.posts = posts
}
@Action({commit: 'updatePosts'})
async function fetchPosts() {
return await get('https://jsonplaceholder.typicode.com/posts')
}Becomes:
actions: {
fetchPosts: async (context) => {
// the return of the function is passed as payload
const payload = await get('https://jsonplaceholder.typicode.com/posts')
// the value of 'commit' in decorator is the mutation used
context.commit('updatePosts', payload)
}
}Complete Module Example
// eg. /app/store/posts.ts
import {VuexModule, Module} from 'vuex-module-decorators'
import {get} from 'axios'
@Module
export default class Posts extends VuexModule {
posts: PostEntity[] = [] // initialise empty for now
get totalComments (): number {
return posts.filter((post) => {
// Take those posts that have comments
return post.comments && post.comments.length
}).reduce((sum, post) => {
// Sum all the lengths of comments arrays
return sum + post.comments.length
}, 0)
}
@Mutation
updatePosts(posts: PostEntity[]) {
this.posts = posts
}
@Action({commit: 'updatePosts'})
async function fetchPosts() {
return await get('https://jsonplaceholder.typicode.com/posts')
}
}Complete Module Example
// equivalent eg. /app/store/posts.js
module.exports = {
state: {
posts: []
},
getters: {
totalComments: (state) => {
return state.posts
.filter((post) => {
return post.comments && post.comments.length
})
.reduce((sum, post) => {
return sum + post.comments.length
}, 0)
}
},
mutations: {
updatePosts: (state, posts) => {
// 'posts' is payload
state.posts = posts
}
},
actions: {
fetchPosts: async (context) => {
// the return of the function is passed as payload
const payload = await get('https://jsonplaceholder.typicode.com/posts')
// the value of 'commit' in decorator is the mutation used
context.commit('updatePosts', payload)
}
}
}Becomes:
Mutation-Actions
import { Module, VuexModule, MutationAction } from 'vuex-module-decorators'
import { ConferencesEntity, EventsEntity } from '@/models/definitions'
@Module
export default class HGAPIModule extends VuexModule {
conferences: Array<ConferencesEntity> = []
events: Array<EventsEntity> = []
// 'events' and 'conferences' are replaced by returned object
// whose shape must be `{events: {...}, conferences: {...} }`
@MutationAction({ mutate: ['events', 'conferences'] })
async fetchAll() {
const response: Response = await getJSON('https://hasgeek.github.io/events/api/events.json')
return response
}
}Namespaced Modules
@Module({ namespaced: true, name: 'mm' })
class MyModule extends VuexModule {
wheels = 2
@Mutation
incrWheels(extra: number) {
this.wheels += extra
}
get axles() {
return this.wheels / 2
}
}const store = new Vuex.Store({
modules: {
mm: MyModule
}
})When creating the store:
Dynamic Modules
// @/store/index.ts
import Vuex from 'vuex'
const store = new Vuex.Store({
/*
Ideally if all your modules are dynamic
then your store is registered initially
as a completely empty object
*/
})1. Create the store
// @/store/modules/MyModule.ts
import store from '@/store'
import {Module, VuexModule} from 'vuex-module-decorators'
@Module({dynamic: true, store, name: 'mm'})
export default class MyModule extends VuexModule {
/*
Your module definition as usual
*/
}2. Create the dynamic module
Usage in components
store.commit('updatePosts', posts)
await store.dispatch('fetchPosts')Standard way
import { getModule } from 'vuex-module-decorators'
import Posts from `~/store/posts.js`
const postsModule = getModule(Posts)
// access posts
const posts = postsModule.posts
// use getters
const commentCount = postsModule.totalComments
// commit mutation
postsModule.updatePosts(newPostsArray)
// dispatch action
await postsModule.fetchPosts()Using getModule
Vuex Module Decorators
By adrianrc
Vuex Module Decorators
- 3,306