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

Posted

技术标签:

【中文标题】Vuex-module-decorator,修改动作内部的状态【英文标题】:Vuex-module-decorator, modifying state inside an action 【发布时间】:2019-06-05 05:57:45 【问题描述】:

使用 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"]

我不明白的是它适用于@MutationActionasync。但是我错过了返回类型Promise&lt;Principal&gt;

@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 中返回特定类型。

【问题讨论】:

您找到解决方案了吗?我遇到了同样的错误... 嗨,道格拉斯。不,不是。我仍然不能有一个@MutationAction 来返回一个键入良好的Promise。我的解决方案是使用@MutationAction 来定义将要更改的内容“mutate=..”。我不使用返回的承诺,而是对商店的变化做出反应。好的部分是所有内容都定义在商店中。但不好的部分是组件发送的操作的效果不太清楚。 我也遇到了这样的事情。我试过 @Action(rawError: true) 没有它。我的理解是 rawError 应该解决这个问题,但对我来说它在生产中运行良好,但我在开玩笑的单元测试中遇到奇怪的错误。看来这个包没有引起太多关注 我遇到同样的错误,但仍然无法找到解决方案。 @GregVeres 有任何更新吗? @kuba1999 我能够让代码在生产中工作,但不能在单元测试中工作,因为我相信单元测试是产品开发的重要组成部分,所以我放弃了 vuex-module-decorator .我现在正在将 chris fitz 的样板转换为 typescript 并以此为起点。 【参考方案1】:

只需将 rawError 选项添加到注释中,使其变为

   @Action(rawError: true)

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

【讨论】:

【参考方案2】:

如果您愿意,可以否决这个答案,因为它没有回答所提出的具体问题。相反,我建议如果你使用 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 本身可能成为引用。但我必须先检查一下。

【讨论】:

以上是关于Vuex-module-decorator,修改动作内部的状态的主要内容,如果未能解决你的问题,请参考以下文章

“InitializeComponent”方法中的代码由设计者生成,不应手动修改。

unity怎么对手动添加的component进行修改

WPF实现鼠标拖动控件并带有中间动效

PS制作动图

怎么更改文件修改时间?

tween.js