【问题标题】:Where should errors from REST API calls be handled when called from in vuex actions?从 vuex 操作中调用时,应该在哪里处理来自 REST API 调用的错误?
【发布时间】:2020-02-19 14:39:05
【问题描述】:

我有一个典型的场景,我在 vuex 操作中调用 REST API 来获取一些数据,然后我将其提交给突变。 我使用 async/await 语法和 try/catch/finally 块。我的 vuex 模块看起来像这样:

const state = {
  users: null,
  isProcessing: false,
  operationError: null
}

const mutations = {
  setOperationError (state, value) {
    state.operationError = value
  },
  setIsProcessing (state, value) {
    state.isProcessing = value
    if (value) {
      state.operationError = ''
    }
  },
  setUsers(state, value) {
    state.users= value
  }
}

const actions = {
  async fetchUsers ({ commit }) {
    try {
      commit('setIsProcessing', true)

      const response = await api.fetchUsers()
      commit('setUsers', response.result)
    } catch (err) {
      commit('setUsers', null)
      commit('setOperationError', err.message)
    } finally {
      commit('setIsProcessing', false)
    }
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

请注意,我在 vuex 操作中处理 catch(err) { } 并且不会重新抛出该错误。我只是将错误消息保存在状态中,然后将其绑定到 vue 组件中以显示 operationError 是否为真。这样我想保持 vue 组件免受错误处理代码的影响,比如 try/catch。

我想知道使用这种模式是否正确?有没有更好的方法来处理这种常见情况?我应该在 vuex 操作中重新抛出错误并让它传播到组件吗?

【问题讨论】:

    标签: vue.js vuex


    【解决方案1】:

    我通常做的是对要发布的数据进行包装,用于处理 api 请求并存储错误。这样,您的用户对象可以将错误记录在其自身上,如果存在任何错误,您可以在组件中使用它们。

    例如:

    import { fetchUsers } from '@\Common\api'
    import Form from '@\Utils\Form'
    
    const state = {
      isProcessing: false,
      form: new Form({
        users: null
      })
    }
    
    const mutations = {
      setIsProcessing(state, value) {
        state.isProcessing = value
      },
      updateForm(state, [field, value]) {
       state.form[field] = value
      }
    }
    
    const actions = {
      async fetchUsers ({ state: { form }, commit }) {
        let users = null
        commit('setIsProcessing', true)
    
        try {
          users = await form.get(fetchUsers);
        } catch (err) {
          // - handle error
        }
    
        commit('updateForm', ['users', users])
        commit('setIsProcessing', false)
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    

    然后在组件中,您可以像这样使用包装器上的错误对象:

    <template>
      <div>
        <div class="error" v-if="form.erros.has('users')">
          {{ form.errors.get('users') }}
        </div>
        <ul v-if="users">
          <li v-for="user in users" :key="user.id">{{ user.username }}</li>
        </ul>
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    export default {
      computed: {
        ...mapState('module' ['form']),
        users () {
          return this.form.users
        }
    }
    </script>
    

    这只是我个人的方法,我觉得它非常方便,到目前为止它对我很有帮助。不知道是否有任何标准模式,或者是否有明确的“正确方法”来做到这一点。

    我喜欢包装方法,因为当来自 api 的响应返回错误时,您的错误会自动响应。

    您可以在 vuex 之外重新使用它,甚至可以更进一步,将错误注入到充当包装器组件的预定义错误边界中,并使用提供/注入方法将错误数据沿组件树传播并显示在哪里您是否需要他们出现。

    这是错误边界组件的示例:

    <template>
      <div>
        <slot></slot>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        module: {
          type: String,
          required: true,
          validator: function (value) {
            return ['module1', 'module2'].indexOf(value) !== -1
          }
        },
        form: {
          type: String,
          default: 'form'
        }
      },
      provide () {
        return {
          errors: this.$store.state[this.module][this.form].errors
        }
      }
    }
    </script>
    
    

    包装应该收到错误的应用程序的某些部分:

    <template>
      <div id="app">
        <error-boundary :module="module1">
          <router-view/>
        </error-boundary>
      </div>
    </template>
    

    然后您可以在子组件中使用用户包装器中的错误,如下所示:

    如果你有一个全局错误,比如没有来自 api 的响应,并希望在侧边栏中显示它

    <template>
      <div id="sidebar">
        <div v-if="errors.has('global')" class="error">
          {{ errors.get('global').first() }}
        </div>
        ...
      </div>
    </template>
    <script>
    export default {
      inject: [
        'errors'
      ],
      ...
    }
    </script>
    
    

    并且相同的错误对象在小部件内的某处被重新使用以用于用户对象验证的错误:

    <template>
      <div id="user-list">
        <div v-if="errors.has('users')" class="error">
          {{ errors.get('users').first() }}
        </div>
        ...
      </div>
    </template>
    <script>
    export default {
      inject: [
        'errors'
      ],
      ...
    }
    </script>
    
    

    Jeffrey Way 不久前在 Vue2 上做了一个系列,他提出了类似的建议。以下是关于可以构建的 Form 和 Error 对象的建议:https://github.com/laracasts/Vue-Forms/blob/master/public/js/app.js

    【讨论】:

      猜你喜欢
      • 2018-09-25
      • 2017-05-23
      • 2020-09-22
      • 1970-01-01
      • 2022-09-30
      • 2018-10-17
      • 2022-01-23
      • 2020-07-26
      • 1970-01-01
      相关资源
      最近更新 更多