Vuex-модуль-декоратор, изменяющий состояние внутри действия

С помощью 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: вы пытаетесь получить доступ к this.someMutation() или this.someGetter внутри @Action? Это работает только в динамических модулях. Если не динамическое, используйте 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,

3 ответа

Просто добавьте опцию rawError в аннотацию, чтобы она стала

   @Action({rawError: true})

И он нормально отображает ошибку. это связано с тем, что библиотека "vuex-module-decorators" оборачивает ошибку, поэтому, сделав это, вы сможете получить RawError, с которым можете работать

Вы можете проголосовать за этот ответ, если хотите, потому что он не отвечает на конкретный вопрос. Вместо этого я собираюсь предложить, чтобы, если вы используете машинописный текст, не используйте vuex. Я потратил последний месяц, пытаясь изучить vue / vuex и машинописный текст. Единственное, чему я привержен - это использование машинописного текста, потому что я твердо верю в преимущества использования машинописного текста. Я больше никогда не буду использовать необработанный javascript.

Если бы кто-то сказал мне не использовать vuex с самого начала, я бы спас себя 3 из последних 4 недель. Поэтому я здесь, чтобы попытаться поделиться этим пониманием с другими.

Ключ - это новая реализация ref в Vue 3. Это то, что действительно меняет правила игры для vuex и машинописного текста. Это позволяет нам не полагаться на vuex для автоматического переноса состояния в реактивное состояние. Вместо этого мы можем сделать это сами с помощью конструкции ref в vue 3. Вот небольшой пример из моего приложения, которое использует ref и класс машинописного текста, в котором я ожидал использовать vuex в прошлом.

ПРИМЕЧАНИЕ 1: единственное, что вы теряете при использовании этого подхода, - это инструменты vuex dev. ПРИМЕЧАНИЕ 2: я могу быть предвзятым, так как я перенес 25000 строк машинописного текста (с 7000 юнит-тестами) из Knockout.js в Vue. Knockout.js был посвящен предоставлению Observables (ссылка Vue) и привязке. Оглядываясь назад, я могу сказать, что это вроде как опережало свое время, но не получило поддержки и поддержки.

Хорошо, давайте создадим класс модуля vuex, который не использует vuex. Поместите это в appStore.ts. Для упрощения он будет просто включать информацию о пользователе и идентификатор клуба, в который он вошел. Пользователь может переключаться между клубами, поэтому для этого есть действие.

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();
}

или в компоненте на основе композиции Api. Это то, что заменит 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 может сам стать ссылкой. Но сначала я должен это проверить.

Я предлагаю это простое решение, оно отлично работает для меня:

      // 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

Другие вопросы по тегам