首页 > 解决方案 > 如何在 Vue.js 中加载数据之前延迟“未找到”错误

问题描述

我正在走这条路:http://site.dev/person/1

我的组件看起来像这样:

// PeopleComponent.vue

<template>

<div>
   <template v-if="person == null">
       <b>Error, person does not exist.</b>
   </template>

   <template v-else>
       <pre> {{ person }} </pre>
   </template>
</div>

</template>

<script>
export default {


    mounted() {
      this.$store.dispatch('getPeople');
    }

    computed: {

      // represents the person whose id potentially matches the value of `/:id` in route.
      person(){ 
          let id = parseInt(this.$route.params.id)
          let person = null

          if(id > 0)
              person = this.$store.state.people.find(p => p.id == id)

          return person;
      }

    }



}
</script>

// [styles]

我在这个组件中做什么:

我的 URL 中有一个 ID。ID 表示此页面上显示的特定资源。我有一个person()计算属性来从我的 Vuex 商店中检索其 ID 与 URL 中的参数匹配的对象。

期望的结果:

在页面顶部,如果找不到对象(例如,有人键入了在商店的对象数组中不存在的 ID),我想显示一条错误消息。如果找到该项目,则可以简单地转储该对象。这目前有效,但是从 API 获取数据和在存储中找到正确对象之间的延迟似乎刚刚足够长,以简要显示错误消息,就好像在页面首次加载时找不到对象一样。当使用较慢的网络速度进行测试时,此错误消息会显示几秒钟。我想消除它,如果对象存在,它根本不会出现。

我试过的:

一些指点将不胜感激,谢谢!


2020 年 3 月 31 日更新

根据 Phil 的建议,我尝试加入一个标志来指示页面何时准备就绪。我以两种不同的方式做到了。

方法 #1 制作了mounted()“异步”并在people从我的 API 检索的操作上添加了等待。之后将标志设置为真:

async mounted() { 

  await this.$store.dispatch('getPeople');
  this.loaded = true;

}

但我仍然简要地看到错误消息。

方法#2

在操作上使用then回调,并将标志设置为true回调内部

mounted() {

  let vm = this

  vm.$store.dispatch('getPeople').then(() => {

      vm.loaded = true;

  })

}

这两种方法都不会阻止消息的出现。

我怀疑这是正在发生的事情:

核心规则

错误应该只显示如果loaded=trueperson=null

  1. 页面加载,loadedfalsepersonnull。错误不会显示。
  2. Page 进行调用以从 API 中获取人员。错误仍然没有显示。
  3. 调用后,loaded已设置为true [此时,计算属性loaded已解决trueperson尚未解决,这就是我相信我看到错误的地方。]
  4. Computed 属性在下一个报价时从存储中找到相关记录。
  5. Person不再是null,因此错误消失了。

编辑 01/04/2020

回答菲尔的问题:What does your getPeople() action look like?


getPeople({ commit })  {   
        axios.get('/get/people')
        .then(response => {
            commit("getPeople", response.data);
        })
        .catch(error => {
            console.log(error);
        })
},

标签: javascriptvue.jsvuejs2

解决方案


听起来您还需要一种状态,例如loading

getPeople将您的操作更改为可组合的,即返回AxiosPromise以便它等待异步任务完成...

getPeople ({ commit })  {
  // make sure you return the promise
  return axios.get('/get/people').then(response => {
    commit("getPeople", response.data)
  }).catch(error => {
    console.error(error)
    // also make sure you don't accidentally convert this to a successful response
    return Promise.reject(error)
  })
},

然后尝试这样的事情

export default {
  data: () => ({ loading: true }),
  async created () {
    // "created" fires earlier than "mounted"
    await this.$store.dispatch('getPeople')
    this.loading = false
  },
  computed: {
    // etc
  }
}

现在您可以loading在模板中使用

<div v-if="loading">Loading...</div>
<div v-else>
  <!-- your "person" template stuff goes here -->
</div>

推荐阅读