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

ger*_*s.b 5 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
Run Code Online (Sandbox Code Playgroud)

但这失败,并显示以下消息:

未处理的承诺拒绝错误:“ ERR_ACTION_ACCESS_UNDEFINED:您是否要尝试在@Act​​ion中访问this.someMutation()或this.someGetter?仅在动态模块中有效。如果不是动态的,请使用this.context.commit(” mutationName“,有效负载)和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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

-

目前,我感到受阻,并希望获得一些帮助来实现一个@Action可以改变状态并在中返回特定类型的Promise

mwa*_*ben 9

只需在注释中添加 rawError 选项,它就会变成

   @Action({rawError: true})
Run Code Online (Sandbox Code Playgroud)

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


Gre*_*res 6

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

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

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

NOTE1:使用这种方法时你失去的一件事是 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();
Run Code Online (Sandbox Code Playgroud)

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

import { appModule } from 'AppStore';

...
if (appModule.loaded.value) {
  const userName = appModule.fullName();
}
Run Code Online (Sandbox Code Playgroud)

或在基于 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>
Run Code Online (Sandbox Code Playgroud)

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

希望有帮助。

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