【问题标题】:How to let vue component wait until the data is ready for render?如何让 vue 组件等到数据准备好渲染?
【发布时间】:2020-08-07 14:37:18
【问题描述】:

vue 组件使用 axios get 不会等待控制器的数据,它会提示错误:

index.vue?d4c7:200 Uncaught (in promise) TypeError: Cannot read property 'ftth' of undefined

我的代码如下:

<template>
    <div class="dashboard-editor-container">
        <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
            <line-chart :chart-data="lineChartData"/>
        </el-row>
    </div>
</template>

<script>
    import LineChart from './components/LineChart';
    import axios from 'axios';

    const lineChartData = {
        all: {
            FTTHData: [],
            VDSLData: [],
            ADSLData: [],
        },
    };
    export default {
        name: 'Dashboard',
        components: {
            LineChart,
        },
        data() {
            return {
                lineChartData: lineChartData.all,
            };
        },
        created() {
            this.getData();
        },
        methods: {
            handleSetLineChartData(type) {
                this.lineChartData = lineChartData[type];
            },
            async getData() {
                axios
                    .get('/api/data_graphs')
                    .then(response => {
                        console.log(response.data);
                        var data = response.data;
                        var i = 0;
                        for (i = Object.keys(data).length - 1; i >= 0; i--) {
                            lineChartData.all.FTTHData.push(data[i]['ftth']);
                            lineChartData.all.VDSLData.push(data[i]['vdsl']);
                            lineChartData.all.ADSLData.push(data[i]['adsl']);
                        }
                    });
            },
        },
    };
</script>

我必须使用watch方法吗?

【问题讨论】:

  • 请分享您的代码
  • 使用 v-if 和 v-else 来决定是否显示组件。我在从服务器检索数据之前显示了一个加载组件
  • 您正在使用没有等待的异步,但不是这里的问题。 console.log 打印什么?
  • 当 console.log "data[i]['f​​tth']" 它说 "index.vue?d4c7:207 Uncaught (in promise) TypeError: Cannot read property 'ftth' of undefined at eval ”。也许是因为我在控制器中使用了 foreach,这就是为什么将数据传递给 vue 需要时间?
  • @Savlon,经过大量调试。谢谢你的帮助:) 我也用 axios 超时。

标签: laravel vue.js vue-component


【解决方案1】:

首先,因为您有这样一个嵌套的数据结构,所以您需要一个计算属性来返回数据是否已加载。通常,您可以在模板中执行此检查。

computed: {
  isDataLoaded() {
    const nestedLoaded = Object.keys(this.lineChartData).map(key => this.lineChartData[key].length !== 0)
    return this.lineChartData && nestedLoaded.length !== 0
  }
}

您可以使用v-if="isDataLoaded" 隐藏元素,直到数据加载完毕。

【讨论】:

  • 你是个天才,它行得通。没有在 axios 中使用超时。感谢您提供此代码:)
  • 你知道如何让vue-component等待一分钟以上再渲染数据吗?我对数据库的查询需要超过 1 分钟。
  • 我不确定是否有任何用户会坐等 1 分钟等待您的数据加载。您最好考虑优化查询的方法,和/或在后台处理它,同时让用户在您的应用中执行其他操作。
【解决方案2】:

目前尚不清楚response.data 的外观,但因为您使用的是Object.keys,所以我假设它是一个对象。

如果您需要遍历键,那么在使用数字索引时您很可能不会得到对象。因此,您需要获取 key 和索引 i 并使用该值来访问该对象。改变这个:

for (i = Object.keys(data).length - 1; i >= 0; i--) {
  lineChartData.all.FTTHData.push(data[i]['ftth']);
  lineChartData.all.VDSLData.push(data[i]['vdsl']);
  lineChartData.all.ADSLData.push(data[i]['adsl']);
}

到这里:

const keys = Object.keys(data)
for (i = keys.length - 1; i >= 0; i--) {
  lineChartData.all.FTTHData.push(data[keys[i]]['ftth']);
  lineChartData.all.VDSLData.push(data[keys[i]]['vdsl']);
  lineChartData.all.ADSLData.push(data[keys[i]]['adsl']);
}

但是对于循环对象的键更容易使用:

for (let key in data) {
  lineChartData.all.FTTHData.push(data[key]['ftth']);
  lineChartData.all.VDSLData.push(data[key]['vdsl']);
  lineChartData.all.ADSLData.push(data[key]['adsl']);
}

替代语法将为您提供密钥,我认为更容易阅读。

【讨论】:

  • 你的回答很有用:)
【解决方案3】:

同时:

使用设置 Axios Timeout 5000ms

axios
.get('/api/data_graphs', { timeout: 5000 })
.then(response => {
  console.log(response.data);
  var data = response.data;
  var i = 0;
  for (i = Object.keys(data).length - 1; i >= 0; i--) {
    lineChartData.all.FTTHData.push(data[i]['ftth']);
    lineChartData.all.VDSLData.push(data[i]['vdsl']);
    lineChartData.all.ADSLData.push(data[i]['adsl']);
  }
  this.lineChartIsLoaded = true;
});

在 vue 组件中使用 v-if

<line-chart v-if="lineChartIsLoaded" :chart-data="lineChartData" :date-data="dateData" />

将 lineChartIsLoaded 默认设置为 false

const lineChartIsLoaded = false;

【讨论】:

  • 使用 5 秒计时器是一种竞争条件;如果时间超过 5 秒,则无法从本质上解决问题,并且会对您的用户体验造成重大影响。
  • 这也是我的经验,但现在我将使用它,因为我仍在寻找解决方案。
  • 我看错了,我以为你在使用 setTimeout。 axios 设置超时只是当 axios 决定停止尝试获取数据时。您应该可以毫无问题地删除它。使用v-ifisLoaded 变量是正确的解决方案。
【解决方案4】:

您可以在加载真实数据之前在数据属性中写入虚拟数据

all: {
  FTTHData: ["Loading..."],
  VDSLData: ["Loading..."],
  ADSLData: ["Loading..."],
},

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-23
    • 2017-05-14
    • 2020-03-28
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多