Vuex模块装饰器,修改操作内部的状态



使用vuex模块装饰器我有一个authenticate操作,应该会改变状态。

@Action
public authenticate(email: string, password: string): Promise<Principal> {
this.principal = null;
return authenticator
.authenticate(email, password)
.then(auth => {
const principal = new Principal(auth.username);
this.context.commit('setPrincipal', principal);
return principal;
})
.catch(error => {
this.context.commit('setError', error);
return error;
});
}
// mutations for error and principal

但失败的消息如下:

未处理的承诺拒绝错误:"ERR_ACTION_ACCESS_UNDEFINED:您试图在@ACTION中访问this.someMutation()或this.someGetter吗?这只适用于动态模块。如果不是动态的,请使用this.context.commit("mutationName",payload)和this.context.getters["getterName"]

我不明白的是,它能很好地与@MutationActionasync配合使用。但是我错过了返回类型Promise<Principal>

@MutationAction
public async authenticate(email: string, password: string) {
this.principal = null;
try {
const auth = await authenticator.authenticate(email, password);
return { principal: new Principal(auth.username), error: null };
} catch (ex) {
const error = ex as Error;
return { principal: null, error };
}
}

--

此时,我感到被阻止了,希望能帮助实现一个@Action,它可以改变状态并返回Promise中的特定类型。

只需将rawError选项添加到注释中,即可成为

@Action({rawError: true})

并且正常显示错误。这是因为图书馆;vuex模块装饰器";包装错误,所以通过这样做,你将能够得到一个RawError,你可以使用

如果你愿意,你可以投票否决这个答案,因为它没有回答提出的特定问题。相反,我建议,如果您使用的是typescript,那么就不要使用vuex。在过去的一个月里,我一直在努力学习vue/vuex和打字脚本。我致力于使用打字稿,因为我坚信使用打字稿的好处。我再也不会使用原始javascript了。

如果有人从一开始就告诉我不要使用vuex,我会在过去的4周里挽救自己的3周。因此,我在这里试图与其他人分享这一见解。

关键是Vue 3的新ref实现。这才是真正改变vuex和typescript游戏的地方。它使我们不必依赖vuex来自动将状态包裹在反应状态中。相反,我们可以通过vue3中的ref构造自己来实现这一点。下面是我的应用程序中的一个小例子,它使用ref和一个typescript类,我过去希望在其中使用vuex。

注1:使用这种方法会损失一件事,那就是vuex-dev工具。注2:我可能有偏见,因为我从Knockout.js移植了25000行typescript(7000个单元测试)到Vue。Knockout.js就是提供Observables(Vue的ref)和绑定。回过头来看,它有点超前,但没有得到追随者和支持。

好的,让我们创建一个不使用vuex的vuex模块类。把它放在appStore.ts中。为了简化,它只包括用户信息和用户登录的俱乐部id。用户可以切换球杆,这样就有了动作。

export class AppClass {
public loaded: Ref<boolean>;
public userId: Ref<number>;
public userFirstName: Ref<string>;
public userLastName: Ref<string>;
// Getters are computed if you want to use them in components
public userName: Ref<string>;
constructor() {
this.loaded = ref(false);
initializeFromServer()
.then(info: SomeTypeWithSettingsFromServer) => {
this.userId = ref(info.userId);
this.userFirstName = ref(info.userFirstName);
this.userLastName = ref(info.userLastName);
this.userName = computed<string>(() => 
return this.userFirstName.value + ' ' + this.userLastName.value;
}
}
.catch(/* do some error handling here */);
}
private initializeFromServer(): Promise<SomeTypeWithSettingsFromServer> {
return axios.get('url').then((response) => response.data);
}
// This is a getter that you don't need to be reactive
public fullName(): string {
return this.userFirstName.value + ' ' + this.userLastName.value;
}
public switchToClub(clubId: number): Promise<any> {
return axios.post('switch url')
.then((data: clubInfo) => {
// do some processing here
}
.catch(// do some error handling here);
}
}
export appModule = new AppClass();

然后,当你想在任何地方访问appModule时,你最终会这样做:

import { appModule } from 'AppStore';
...
if (appModule.loaded.value) {
const userName = appModule.fullName();
}

或者在基于compositionApi的组件中。这将取代mapActions等

<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import { appModule } from '@/store/appStore';
import footer from './footer/footer.vue';
export default defineComponent({
name: 'App',
components: { sfooter: footer },
props: {},
setup() {
return { ...appModule }
}
});
</script>

现在您可以在模板中使用userId、userFirstName、userName等。

希望能有所帮助。

我刚刚添加了计算getter。我需要测试一下是否真的需要。可能不需要它,因为您可能只需要在模板中引用fullName(),并且由于fullName()引用了其他引用的.value变量,fullName本身可能会成为一个引用。但我必须先检查一下。

我建议这个简单的解决方案,对我来说很好👌:

// In SomeClassComponent.vue
import { getModule } from "vuex-module-decorators";
import YourModule from "@/store/YourModule";
someMethod() {
const moduleStore = getModule(YourModule, this.$store);
moduleStore.someAction();
}

如果操作有参数,请将其放入。取自:https://github.com/championswimmer/vuex-module-decorators/issues/86#issuecomment-464027359

最新更新