如何让 vue 组件等到数据准备好渲染?
Posted
技术标签:
【中文标题】如何让 vue 组件等到数据准备好渲染?【英文标题】:How to let vue component wait until the data is ready for render? 【发布时间】: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]['ftth']" 它说 "index.vue?d4c7:207 Uncaught (in promise) TypeError: Cannot read property 'ftth' of undefined at eval ”。也许是因为我在控制器中使用了 foreach,这就是为什么将数据传递给 vue 需要时间? @Savlon,经过大量调试。谢谢你的帮助:) 我也用 axios 超时。 【参考方案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-if
和isLoaded
变量是正确的解决方案。【参考方案4】:
您可以在加载真实数据之前在数据属性中写入虚拟数据
all:
FTTHData: ["Loading..."],
VDSLData: ["Loading..."],
ADSLData: ["Loading..."],
,
【讨论】:
以上是关于如何让 vue 组件等到数据准备好渲染?的主要内容,如果未能解决你的问题,请参考以下文章