使用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"]
我不明白的是,它能很好地与@MutationAction
和async
配合使用。但是我错过了返回类型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