灵魂拷问:v-if和v-show你真的用对了吗? | 创作者训练营第二期

307 阅读2分钟

前言

  • 在线音乐戳我呀!
  • 音乐博客源码上线啦!
  • 从接项目并跑通项目成功运行起,打开控制台的那一刻,我哭了,狂报错,虽然页面上能走通,但控制台红色报错多多,我决定好好整顿!
  • 像报错置之不理的程序员,是你吗?,秀儿。
  • 接下来我们拎一个报错来介绍一下事情的起因。

目前存在的问题?

打开控制台,给我报了Cannot read property 'floodingData' of null

下面我们分析为什么会存在该问题。

场景

有一个页面,显示六张图,会根据时间轴切换进行数据的更新。

可就在切换时间轴的时候,报错了。

为什么会出现此问题?

当点击按钮的时候,会去请求一次接口,还没有等接口返回回来,再点击按钮,在去请求一次接口,这个过程控制台报错Cannot read property 'floodingData' of null

v-for循环报错,对象null。

对此进行分析:

当点击按钮的时候,会去请求一次接口,还没有等接口返回回来,再点击按钮,在去请求一次接口,这时会取消上一次接口,等待第二次接口的返回的过程,this.info已经为null了,而我们的for循环,risk数组是有值的,但info为null,第一次循环是info.floodingData.number,info为null,自然报错Cannot read property 'floodingData' of null

<button @click="timeClick">时间轴</button>
<el-badge
    v-for="(riskItem, riskItemIndex) in risk"
    :value="
    info[riskItem.key].number > 0 ? info[riskItem.key].number : ''
    "
    :key="riskItemIndex"
>
    <p>{{ riskItem.title }}</p>
</el-badge>

data(){
    return {
        risk:[
          {
            key: 'floodingData',
            title: '江河超警洪水',
            img: require('./image/flooding.png')
          },
          {
            key: 'waterloggedAreaData',
            title: '城乡低洼积涝',
            img: require('./image/waterloggedArea.png')
          },
          {
            key: 'transferNowLevelData',
            title: '山洪灾害风险',
            img: require('./image/transferNowLevel.png')
          }
        ],
        info: {
            floodingData: {
              number: null
            },
            waterloggedAreaData: {
              number: null
            }
        },
        cancelToken: this.axios.CancelToken.source()
	}
}

timeClick(){
	 // 取消上一次请求 
      this.cancelToken.cancel()
      this.cancelToken = this.axios.CancelToken.source()
	   this.axios
        .get(
          window.publicPath + urls.appSvc + 'RiskData',
          {
            params,
            cancelToken: this.cancelToken.token
          }
        ).then(res =>{
        	this.info = res
        }).catch(e =>{
        	this.info = null
        }) 
}

risk数组无论如何是有值的,但info可能会没值,需要通过risk的key作为info去获取对应的数据。

解决方案

在for循环之前加个v-if判断一下info,为true才去渲染。

Tip:使用v-show是无效的,因为不管是什么条件,都会渲染,那还是会报错,只有v-if条件为true才会去渲染

代码如下

<template v-if="info">
    <el-badge
        v-for="(riskItem, riskItemIndex) in risk"
        :value="
        info[riskItem.key].number > 0 ? info[riskItem.key].number : ''
        "
        :key="riskItemIndex"
    >
        <p>{{ riskItem.title }}</p>
    </el-badge>
</template>

知识库

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

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

知识点

v-showv-if

以往推荐

Vue-Cli3搭建组件库

Vue实现动态路由(和面试官吹项目亮点)

项目中你不知道的Axios骚操作(手写核心原理、兼容性)

VuePress搭建项目组件文档

koa2+vue+nginx部署

vue-typescript-admin-template后台管理系统

原文链接

juejin.cn/post/695566…