前言

这个标题不太好取。

本文需要下面的知识:

https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com

问题描述

我最近的一个功能需求是通过axios获取我存储在COS中的json文件,同时渲染到页面上。

而问题就是,axios可以成功获取数据,组件也可以成功渲染,但是控制台会报错

[Vue warn]: Error in render: "TypeError: Cannot read property 'text' of undefined"。

问题分析

首先,我的情况比我已经查到的博主们的问题更为复杂。

我的json文件部分内容如下:

{"0": {"headline": "如何快速调整显示器组的亮度?","url": "zhuanlan.zhihu.com/p/259647484","dateP": "2020-09-26T13:35:07.000Z","dateM": "2020-09-26T13:37:24.000Z","img": "https://pic2.zhimg.com/v2-8b58a57ba0923d23329abc16766da34c_r.jpg","text": "前言 Mac的情况我不清楚,但是Windows下调整显示器亮度其实是一个挺烦人的事。 我的显示器组为一个15.6寸的副屏,一个22寸的显示器,一个15.6寸的笔记本屏幕。 由于硬件原因,通过显示器本身调整亮…"},"1": {"headline": "通过Vue实现vw/vh自适应单位","url": "zhuanlan.zhihu.com/p/257866252","dateP": "2020-09-22T10:51:08.000Z","dateM": "2020-09-22T10:51:08.000Z","img": "https://pic4.zhimg.com/v2-8ac0ec7ef990ca579657ae5b8bea714c_r.jpg","text": "前言 虽然现在可能响应式布局多一些,但是我还是觉得自适应单位比较好用。对于一些框架的UI组件,例如Vuetify,可能并不支持使用自适应单位,此时就会非常影响布局效果。 这篇文章提供的方法可以帮助你实现这…"},"2": {"headline": "如何DIY便携显示器?","url": "zhuanlan.zhihu.com/p/257257464","dateP": "2020-09-21T13:43:08.000Z","dateM": "2020-09-21T13:52:32.000Z","img": "https://pic1.zhimg.com/v2-7f27fabd9fc334d2c7e529561658b82f_r.jpg","text": "前言 最近找工作比较压抑,写几篇文章放松一下。 本文较长,知识点较多,建议收藏或者赞同给自己留个指针(误 便携显示器 便携显示器听名字就能知道,是一种移动的显示器,所以它要满足几个大的需求: 低压供电(相对于传…"},

如果你好奇这个json文件是怎么获取到的,你可以访问:

LikeDreamwalker/zhihu-articles-api​github.com

并且给我一个star!

这个json文件的问题是它是多层的,一般的示例中都是简单的一维数组或者一层的对象。

接下来就是问题的关键,为什么axios已经成功获取到数据,并且组件也已经渲染,但是会报错呢?

undefined意味着当时index[0].text并没有被定义,而却又被调用,即在页面渲染时调用index对象,但是index[0].text还没有被定义,也就是axios还没有得到数据。

那么思路就很简单了,方案1是我们尝试提前写好index对象,即在data中指定

index: {{text=null}}

方案2则是我们让对应组件在axios获取数据之后再渲染组件。

我先解释一下1,1是一个解决方案,但是对于我这种情况,不可控有多少个对象,而每个对象又有诸多属性,这种解决方案治标不治本。但是,当你在声明时应该尽可能按照对象的真实结构声明。如果你和我一样不能解决这个问题,下面也有办法。

当然,如果你的对象很简单,那么到这里就结束了,这可以是一个解决方法。

所以,问题变简单了,核心就是axios到底是在什么时刻获取的数据,并且有没有可能在页面被渲染之前获取数据。

axios在何时获取到数据

axios的一般用法有两种,一种是放在created里,也就是在页面渲染之前,另外一种是放在mounted里,也就是页面渲染之后。

所以我们可以进行尝试,分别写好两种情况:

created() {console.log("start");axios.get("https://ldwid-1258491808.cos.ap-beijing.myqcloud.com/json/doNotUseThisJSON.json")//用于调试本地json//.get("http://localhost:8080/doNotUseThisJSON.json").then(response => {_this.index = response.data;console.log(response.data);console.log(_this.index);console.log(_this.index[0]);});console.log("created");},
mounted() {console.log("start");axios.get("https://ldwid-1258491808.cos.ap-beijing.myqcloud.com/json/doNotUseThisJSON.json")//用于调试本地json//.get("http://localhost:8080/doNotUseThisJSON.json").then(response => {_this.index = response.data;console.log(response.data);console.log(_this.index);console.log(_this.index[0]);});console.log("mounted");}

不出意外的话,你会发现这两种情况依然会抛出undefined的错误。

但是这里与逻辑是相悖的,既然我选择在页面渲染之前获取到数据,为什么依然会报错?

猜测:网络问题

由于axios是异步的,也许在created时,真的执行了axios语句,但是由于网络问题,加载的时间大于语句的执行时间,所以导致获取到数据会在页面渲染之后。

这种猜测是符合逻辑的,但实际上是对JS异步和生命周期理解有问题。请阅读下面这篇文章:

https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com

与其猜测,我们不如看一下具体的执行顺序:

beforeCreate() {console.log("beforCreate");},created() {let _this = this;console.log("start");axios// .get(//   "https://ldwid-1258491808.cos.ap-beijing.myqcloud.com/json/doNotUseThisJSON.json"// ).get("http://localhost:8080/doNotUseThisJSON.json").then(response => {_this.index = response.data;console.log(response.data);console.log(_this.index);console.log(_this.index[0]);});console.log("created");},beforeMount() {console.log("beforMount");},mounted() {console.log("mounted");}

之后我们加载页面:

答案可能会出乎你的意料,虽然axios语句被放在了created下,但是实际上的执行是在mounted之后。

如果你不相信,你还可以把axios放置到其他的生命周期,依然会是这个结果。

所以,axios会在页面完全渲染之后获取到数据。在渲染页面,获得模板字符串与替换字符串的时候,发现引用了并不存在的属性,自然会报错。

axios能不能在页面渲染之前获取到数据

这里需要生命周期和异步的知识:

https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com

首先,axios是异步的,既然是异步,axios语句会在所有的宏任务执行完毕后,才会被访问到,并且按照微任务队列的顺序继续执行。所以,axios不能再页面渲染之前获取到数据。

如果,axios是同步的,当你填写了错误的API或者API失效,这就会导致整个生命周期受阻从而崩溃,最终页面渲染失败。但是很明显,在开发过程中不可能出现这种情况。

而如果你仍然有执念,认为是上面的网络环境问题,如果此时为真,那么axios实际上是另外一个线程,并行于生命周期,但是JavaScript是一个单线程语言。

到这里,整个问题的因果关系应该非常清晰了:

  • 如果想要index[0].text正常解析,我们需要在解析前先填入正确的text属性,此时需要你直接写好index或者让axios在模板解析前将正确的text属性填入
  • 由于生命周期,我们可知axios必须在beforeMount之前完成获取
  • 由于axios的异步特性,axios不能在页面渲染之前完成获取
  • 如果想要如此,必须使axios在另外一个线程中执行,但JavaScript是一个单线程语言

问题解决

在我们知道出现问题的原因之后,解决问题的方式就变得很简单了。

我们在分析中已经知道,解决这个问题有至少两个办法。我们现在来看一下第二个办法。

在axios获取到数据之后渲染对应组件

这里我们使用Vue的条件渲染:

条件渲染 — Vue.js​cn.vuejs.org

既然,我们知道axios会在页面渲染之后执行,那么我们可以人为的添加一个状态,用于标识axios是否获取到数据。而对于对应的模板,仅当该状态为true时才会进行渲染。

如果你很疑惑为什么如此可以实现,你可以重新看一下报错的节点,是在beforeMount之后,在Mounted之前,也就是在模板被解析为模板字符串存储在内存中,但是还没有被渲染到页面上(或者说是即将被渲染在页面上)时,此时Vue不会执行不符合渲染条件的模板内容:

v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

我们修改模板内容:

          <v-card-text v-if="status">{{ index[0].text }}</v-card-text>

修改data:

data: () => ({status: false,index: {}}),

修改axios:

 mounted() {let _this = this;axios.get("https://ldwid-1258491808.cos.ap-beijing.myqcloud.com/json/doNotUseThisJSON.json").then(response => {_this.index = response.data;_this.status = true;});}

此时,再次刷新页面,不会再报错。

务必把status的修改放在.then下而不是mounted下,否则依然不会有效果。

这里需要提醒一下,很多人解决这个问题的办法使用的判断条件是属性本身,使用这个属性作为判断的条件的前提条件是这个属性存在,否则的话undefined依然会被转化为false属性为null也会转化为false,前者在使用时依然会报错undefined此时不会有任何改变,而之所以这个页面依然可以渲染出数据是因为双向绑定使这个属性值在页面被渲染后存在了,自然就会渲染出这个模板内容。

而如果,你可以去声明这样的内容,为什么不直接把完整的对象写好呢?如果完整的对象不便于手工声明,为什么还要使用这个对象的属性值作为判断条件呢?

至于性能,我认为影响甚微,毕竟多声明一个变量不是非常大的运算量。

最后

我不知道你有没有懂,但是我觉得在我爬出这个坑之后对Vue和JavaScript有了全新的认识。

vue 父页面中的方法 调用_解决Vue中页面成功渲染数据undefined的问题相关推荐

  1. vue数据改变渲染问题_解决Vue中页面成功渲染数据undefined的问题

    前言 这个标题不太好取. 本文需要下面的知识:https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com 问题描述 我最近的一个功能需求是通过a ...

  2. vue进入页面执行的钩子函数_解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题...

    项目需求:图片加载时,当鼠标滚动至当前图片进行加载并加上上滑特效,实现这个效果需要对文档文档滚动位置和图片的当前位置进行比较.但是mounted 钩子函数执行时img图片并未加载出来也就是占位为空,导 ...

  3. vue样式中背景图片路径_解决vue打包css文件中背景图片的路径问题

    vue-cli写完的静态页面我们在node环境中引入没有问题,但是打包后放在Apache环境下,路径却有问题了 如一个简单css语句 .welcome { width: 420px; height: ...

  4. java中的方法求和_在Java中模拟求和类型的巧妙解决方法

    java中的方法求和 在继续阅读实际文章之前,我想感谢令人敬畏的Javaslang库的作者Daniel Dietrich ,他在我面前有了这个主意: @lukaseder尝试使用静态方法<T,T ...

  5. vuecli3中src的文件_解决vuecli3中img src 的引入问题

    最近公司要做一个在线ps 的项目 但是后台没写完, 我在用本地图片上传预览的时候 发现图片不能显示, 解决的办法 是 //页面的结构 export default { data() { return ...

  6. vue 父链和子组件索引_解决Vue2.x父组件与子组件之间的双向绑定问题

    最近在研究如何写一套基于Vue2.x的UI组件给自己用,提升一点BIG,在制作含有input的组件遇到一个问题:不知怎样才能把子组件中input与调用者(父组件)的数据实现双向绑定,想过使用Vuex, ...

  7. python中config方法作用_使用Python中的config配置

    Python中有ConfigParser类,可以很方便的从配置文件中读取数据(如DB的配置,路径的配置),所以可以自己写一个函数,实现读取config配置. config文件的写法比较简单,[sect ...

  8. vue、cnpm不是内部文件_解决vue不是内部或者外部命令

    该问题出现后,遍寻解决方法,此时 node 版本 7.x.x ,npm 版本 3.x.x ,使用 npm i vue -g 和 npm i vue-cli -g 下载了好几次,版本为2.x.x 先说一 ...

  9. vue 父刷新子_父组件中vuex方法更新state子组件不能及时更新并渲染的完美解决方法...

    场景: 我实际用到的是这样的,我父组件引用子组件related,父组件调用获取页面详情的方法,更新了state值related,子组件根据该related来渲染相关新闻内容,但是页面打开的时候总是先加 ...

最新文章

  1. LeetCode Sort List(单链表归并排序)
  2. 机器学习中的范数规则化之(二)核范数与规则项参数选择
  3. java enummap_Java EnumMap get()方法与示例
  4. 海奥华预言--第一章 神秘邀请
  5. Eclipse中错误为 Access restriction 的解决方案
  6. No package ‘mate-settings-daemon‘ found
  7. 简单的抓包_学习笔记
  8. 小米 note3 android,小米Note3将更新MIUI10:基于安卓8.1 速度提升明显手感更加丝滑...
  9. 视频教程-webpack基础和完整项目脚手架搭建教程-JavaScript
  10. STM32智能小车第二章 PWM调速
  11. 人工智能数学基础:求导神器--罗必塔法则
  12. 更改C盘用户文件夹名
  13. 长文预警-超详细的熊猫烧香病毒分析_01
  14. 计算机网络管理工程师证书考试试题,网络工程师考试模拟试题四-试题试卷网...
  15. PAT 乙级 1065 单身狗 (25 分)
  16. android 不如 ios,安卓永远不如iOS运行流畅的根本原因
  17. Kaldi语音识别技术
  18. Java架构师成长之路
  19. 【云原生 | 13】手把手教你搭建ferry开源工单系统
  20. 物联网服务器协议命令,物联网使用HTTP协议传输数据

热门文章

  1. 面试必问:InnoDB 中一棵 B+ 树能存多少行数据?
  2. 微信支付的架构真的那么牛吗?
  3. 35岁不是程序员的坎儿,看不清楚这件事才是!
  4. 图解TensorFlow--大数据平台技术栈16
  5. 京东某员工因加班太多引女友不满,下定决心离职:不想被迫加班!
  6. 央视曝光:股市暴跌暴涨,投资的安全感在哪里?
  7. 微服务的分解和组合-文末赠书
  8. 为什么程序员不能接私活?
  9. 你知道标志着团队已经敏捷化的8个信号吗?
  10. 强势安利7个广受好评的软件!助你一臂之力!