仓库地址:https://github.com/championswimmer/vuex-module-decorators
1、使用vuex-module-decorators前,当我们写一个store时,是这样的:
module.exports = {
state: {
num: []
},
getters: {
getfunction: (state) => {
return state.num
.reduce((sum, cout) => {
return sum + cout.comments.length
}, 0)
}
},
mutations: {
update: (state, nums) => {
state.nums = nums
}
},
actions: {
fetch: async (context) => {
const payload = await get(api.update)
context.commit('updatenums', payload)
}
}
}
2、当我们使用vuex-module-decorators时,你的store可以这样写:
import {VuexModule, Module} from 'vuex-module-decorators'
import {get} from 'axios'
@Module
export default class nums extends VuexModule {
nums:[] //相当于state
//get 相当于getters:
get getfunction (): number {
return nums.reduce((sum, cout) => {
return sum + cout.comments.length
}, 0)
}
//使用@Mutation装饰器,相当于Mutation:此时的this指向state
@Mutation
update(nums) {
this.nums = nums
}
//相当于Action:函数内commit时:this.context.commit('mutationName',mutPayload)
@Action({commit: 'updatenums'})
async function fetch() {
return await get(api.update)
}
}
好处:
1、getmodule更安全,当你调用并不存在的state时,类型检查会提示你
const myMod = getModule(MyModule)
myMod.someField //works
myMod.someOtherField //Typescript will error, as field doesn't exist
2、Namespaced Modules、Dynamic Modules
3、详细使用方法
(我们可以与typescript同时使用)
state
import { Module, VuexModule } from 'vuex-module-decorators'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
}
类的所有属性都转换为state,等同于:
export default {
state: {
wheels: 2
}
}
Getters
import { Module, VuexModule } from 'vuex-module-decorators'
@Module
export default class Vehicle extends VuexModule {
wheels = 2
get axles() {
return this.wheels / 2
}
}
所有的get函数都转换为 vuex getter,等同于:
export default {
state: {
wheels: 2
},
getters: {
axles: (state) => state.wheels / 2
}
}
我们还可以返回一个函数:
@Module
export default class Vehicle extends VuexModule {
companies = []
get company() {
return (companyName: string) => { this.companies.find(company => company.name === companyName) };
}
}
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
}
}
用@Mutation 修饰的函数都被转换成Vuex 的mutations,相当于:
export default {
state: {
wheels: 2
},
mutations: {
puncture: (state, payload) => {
state.wheels = state.wheels - payload
}
}
}
⚠️
-
使用@Mutation 装饰器进行装饰后,Mutations
就会把this设置为state,当你想改变state时,例如:state.item++ 就是 this.item++ -
Mutation中不能使用异步函数,也不要将它们定义为箭头函数,因为在runtime会重新绑定,而箭头函数捕获this后无法改变
Action
mport { Module, VuexModule, Mutation, Action } 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)
}
}
所有用@Action 修饰的函数都会转换为vuex action,相当于:
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)
}
}
}
⚠️:
- 由于this已经被绑定为state,当我们commit a mutation 时:可以直接:
this.context.commit('mutationName', mutPayload)
- 这里会将函数包装为promise,适合异步函数,如果你想得到同步函数的结果,你需要放到Mutation中
- 不要用箭头函数
命名空间
@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
}
})
⚠️
- @Module中的name值, 必须要new store({modules: {}})中注册module name名称要一致.
- this.store.dispatch(‘action’)调用需要转换为this.store.dispatch(‘name /action’)
动态module
1、首先我们要有一个store
// @/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
*/
})
2、将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
*/
}
⚠️
- 不支持动态 + 嵌套模块
- 确保你导入的store是存在的
🌰一个完整的例子
store/modules/mytest.ts
import {
VuexModule,
Module,
Mutation,
Action,
getModule,
} from 'vuex-module-decorators';
import * as API from '../../api/mytest';
import store from '../index';//这里导出store
export interface IGoodsItem {}
export interface ITestState {}
@Module({ dynamic: true, store, name: 'mytest' })
class App extends VuexModule implements ITestState {
public mygoods?: IGoodsItem[];
@Mutation
setData(state: ITestState): void {
Object.assign(this, state);
}
@Action({ rawError: true })
async getMyapires(): Promise<ITestState> {
const data = (await API.getMyapires()) || {};
this.context.commit('setData', data);
return data as ITestState;
}
}
export const AppModule = getModule(App);
views/mytest.vue
<template>
<div>将getModule引用到此页面</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { AppModule } from '../store/modules/home';
@Component({})
export default class Mytest extends Vue {
get myList() {
return AppModule.mygoods;
}
mounted(): void {
AppModule.getMyapires();
}
}
</script>
<style lang="scss" scoped>
</style>