12

使用vuex-module-decorator我有一个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"]

我不明白的是它与@MutationActionand配合得很好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可以改变状态并在 a 中返回特定类型的 a Promise

4

2 回答 2

12

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

   @Action({rawError: true})

并且正常显示错误。这是因为库“vuex-module-decorators”包装错误,因此通过这样做,您将能够获得可以使用的 RawError

于 2020-05-17T05:51:45.713 回答
7

如果您愿意,您可以否决这个答案,因为它没有回答所提出的具体问题。相反,我建议如果你使用 typescript,那么不要使用 vuex。过去一个月我一直在尝试学习 vue /vuex 和 typescript。我承诺的一件事是使用打字稿,因为我坚信使用打字稿的好处。我永远不会再使用原始 javascript。

如果有人从一开始就告诉我不要使用 vuex,我会在过去 4 周中节省 3 周。因此,我在这里尝试与他人分享这一见解。

关键是 Vue 3 的新 ref 实现。它是真正改变 vuex 和 typescript 游戏的东西。它使我们不必依赖 vuex 自动将状态包装在响应式中。相反,我们可以自己使用 vue 3 中的 ref 构造来做到这一点。这是我的应用程序中的一个小示例,它使用了 ref 和一个 typescript 类,我过去希望在其中使用 vuex。

注意 1:使用这种方法时你会失去的一件事是 vuex 开发工具。注意 2:我可能有偏见,因为我将 25,000 行 typescript(包含 7000 个单元测试)从 Knockout.js 移植到 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() 引用了其他 refs 的 .value 变量,所以 fullName 本身可能成为引用。但我必须先检查一下。

于 2020-04-03T13:26:07.770 回答