【问题标题】:how to pass a reference to a component when calling a vuex action调用vuex动作时如何传递对组件的引用
【发布时间】:2018-01-29 19:44:01
【问题描述】:

我对 vue 很陌生(对 vuex 也很陌生)。我想将一些 axios api 调用移动为我的 Vuex 商店中的操作。我知道例如:

  actions:{
    LOAD_USER: function ({ commit }) {
      axios.get('/arc/api/v1/me', {dataType: 'json'})
      .then((response )=> {
        commit('SET_USER', { user: response.data.user })
      })
      .catch(function (error) {
        console.log(error.message);
      });

并通过以下方式在我的调用组件中调用它:

  this.$store.dispatch('LOAD_USER')

这是有效的。我的问题是我需要将调用组件中的一些变量设置为 false 或终止进度条。这是我之前在调用组件中使用的内容:

  this.loading = true
  this.$Progress.start()
  axios.get('/arc/api/v1/me', {dataType: 'json'})
  .then((response )=> {
    this.$Progress.finish()
    this.loading = false
    this.$store.state.user = response.data.user;
    this.user = this.$store.state.user
  })
  .catch(function (error) {
    this.$Progress.fail()
    console.log(error.message);
  });

如何将这些加载行为集成到我的 vuex 操作中?我将如何通过此调用传递对我的组件的引用:

  this.$store.dispatch('LOAD_USER')

或者有更好的解决方案吗?

【问题讨论】:

    标签: vue.js vuex


    【解决方案1】:

    嗯,你总是可以使用Store.dispatch() 的第二个参数将任何有效载荷传递给相应的动作:

    this.$store.dispatch('LOAD_USER', this); // passing reference as payload
    

    ...但我强烈建议不要这样做。相反,我宁愿让 VueX 处理整个状态(包括“加载”标志等)。

    在这种情况下,单个 action - LOAD_USER,基于异步 API 请求 - 将提交两个 mutations 到存储:第一个设置 loading 标志,当请求已经启动后,第二个将其重置回false - 并加载用户数据。例如:

    LOAD_USER: function ({ commit }) {
      commit('LOADING_STARTED'); // sets loading to true
      axios.get('/arc/api/v1/me', {dataType: 'json'})
      .then(response => {
        commit('LOADING_COMPLETE'); // resets loading flag
        commit('SET_USER', { user: response.data.user });
      })
      .catch(error => {
        commit('LOADING_ERROR', { error }); // resets loading
        console.log(error.message);
      });
    

    除了其他优点外,这种方法还可以在您的请求逻辑变得更复杂时大大简化事情 - 包括错误处理、重试等。

    【讨论】:

    • 我原则上同意通过动作传递组件真的很难看。但是 LOADING_STARTED / LOADING_COMPLETE 是否会改变 vuex 中的一些底层 is_loading 属性,我现在需要在我的组件中观察这些属性?或者我会将 UI 部分功能带入 vuex(以及我将如何做到这一点?)。抱歉,我几天前才发现 EventBus,觉得如果我能掌握 Vuex,我会更有信心。
    • 不,vuex应该管理状态,vue组件应该代表它(状态变化时变化等)。
    【解决方案2】:

    Actions 可以返回一个 Promise https://vuex.vuejs.org/en/actions.html 我认为您想要做的是在您调用您的操作时激活加载,并在解决或拒绝承诺时停止加载。

    // Action which returns a promise.
    actions: {
      LOAD_USER ({ commit }) {
        return new Promise((resolve, reject) => {
          axios.get('/arc/api/v1/me', {dataType: 'json'})
            .then((response )=> {
              commit('SET_USER', { user: response.data.user })
              resolve()
            })
            .catch(function (error) {
              console.log(error.message);
              reject(error);
            });
        })
      }
    }
    
    // Update loading when the action is resolved.
    this.loading = true;
    store.dispatch('LOAD_USER').then(() => {
      this.loading = false;
    })
    .catch(function(error) {
      // When the promise is rejected
      console.log(error);
      this.loading = false;
    });
    

    如果您无法使用上述方法实现目标,您可以将加载布尔值添加到您的 vuex 存储并将其导入您的组件中。比修改动作中的加载布尔值(使用突变)来让视图更新。

    注意:我不会传递对您的操作的引用。虽然这是可能的,但可能有更好的解决方案来解决您的问题。尽可能将视图逻辑保留在组件中。

    【讨论】:

    • 嗯...所以这也很有趣。返回的 Promise 中有没有办法捕获错误?并在这种情况下运行一些错误代码?
    • @timpone 您可以为此添加 catch,我已经更新了上面的代码。
    猜你喜欢
    • 2020-10-20
    • 2020-08-14
    • 1970-01-01
    • 2017-08-08
    • 2020-12-10
    • 2019-04-20
    • 2016-06-10
    • 2021-12-23
    • 2017-07-24
    相关资源
    最近更新 更多