Vuex-module-decorator,在动作内部修改状态

时间:2019-01-10 11:11:05

标签: vue.js vuex vuex-modules

使用 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:您是否正在尝试在@Act​​ion中访问this.someMutation()或this.someGetter?   这仅在动态模块中有效。   如果不是动态的,请使用this.context.commit(“ mutationName”,有效负载)和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中返回特定类型。

2 个答案:

答案 0 :(得分:5)

只需在标记中添加rawError选项,使其变为

   @Action({rawError: true})

它正常显示错误。这是因为库“ vuex-module-decorators”包装了错误,因此通过执行此操作,您将获得可以使用的RawError

答案 1 :(得分:3)

如果您愿意,可以拒绝该答案,因为它不能回答提出的特定问题。相反,我建议您使用打字稿,而不要使用vuex。在过去的一个月中,我一直在尝试学习vue / vuex和打字稿。我致力于使用打字稿,因为我坚信使用打字稿的好处。我将永远不会再使用原始javascript。

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

关键是Vue 3的新ref实现。真正改变了vuex和Typescript游戏的是什么。它使我们不必依靠vuex来自动将状态包装为反应式。相反,我们可以使用vue 3中的ref构造自己完成操作。这是我的应用程序中的一个小示例,该示例使用ref和一个typescript类,我曾期望在其中使用vuex。

注意1:使用这种方法时,您失去的一件事就是vuex开发工具。 注意2:我可能会因将25,000行的打字稿(带有7000个单元测试)从Knockout.js移植到Vue而产生偏差。 Knockout.js的全部目的是提供Observables(Vue的参考)和绑定。往回看,虽然有点超前,但没有得到支持和支持。

好吧,让我们创建一个不使用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等。

希望有帮助。

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