前端优雅的处理接口返回Json数据中值为null的方案(页面绑值时无需写非空校验,基于TypeScript)

需求背景

最近参与了一个基于Angular的前端项目,在前后端交互的过程中,我们经常会遇到接口返回的Json数据中值为null的情况,如果前端在绑值时不做校验,恰好接口返回的数据值为null时,就会出现报错并给出类似报错信息

 Cannot read property 'xxxx' of undefined

假设正常情况下接口返回的数据格式如下:

{
    "baseInfo": {
        "name": "yuzhiqiang",
        "age": 27,
        "hobby": [
            "吃",
            "喝",
            "玩",
            "乐"
        ]
    },
    "bankCard": [
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国农业银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "信用卡"
        }
    ]
}

则前端对应的model如下:



class Person{
    baseInfo:BaseInfo=new BaseInfo()
    bankCard:BankCard[]=[]
}

/*基本信息*/
class BaseInfo{
  name:string=''
  age:number=0
  hobby:string[]=[]
}

/*银行卡*/
class BankCard{
  no:string=''
  bankName:string=''
  type:string=''
}


理想情况下页面的绑值代码如下:

<div>姓名:{{person.baseInfo.name}}</div>
<div>年龄:{{person.baseInfo.age}}</div>
<br>
<div *ngFor="let item of person.baseInfo.hobby">
  爱好:{{item}}
</div>
<br>
<div *ngFor="let item of person.bankCard">
 <p>银行:{{item.bankName}}</p>
 <p>卡号:{{item.no}}</p>
 <p>银行卡类型:{{item.type}}</p>
</div>


假如接口返回的数据是这样

{
    "baseInfo": null,
    "bankCard": []
  }

按照之前的写法就会报错
在这里插入图片描述

为了解决这种报错并保证项目的 “健壮性”, 在绑值的时候就要先对数据进行校验,代码如下:

<div>姓名:{{person&&person.baseInfo&&person.baseInfo.name?person.baseInfo.name:''}}</div>

这样写确实能解决问题,但是写起来很恶心,我写完第一个就已经受不了了。这样的代码完全没有什么技术含量,还使得页面看起来很乱很复杂。

下面我们来看一下如何能够不写这么多恶心的校验代码,并且保证程序正常的执行。


解决方案

方案一:前后端统一好数据结构以及类型后,接口严格按照标准来返回数据,禁止返回null

这种做法一般是后端定义了个兼容前端model的业务Model,在返回数据给前端的时候做了处理。即使从表中查出来的数据是null,也会给出对应类型的初始值而不是null。
也就是说前端默认接口返回的数据一定是合法的,不会有问题的。

这种方案就需要前后端能够完全的协商好,并且后端愿意配合你这么做才能放心大胆的去用。
但是你没办发保证每一个后端都能帮你做处理,至少我遇到的后台开发很少有人愿意这么做,他们会觉得 完全没必要太麻烦

这种情况下要么你能打赢他,强制他听你的,要么你是他领导,他能听你的话。
但是我断定跟你合作的后端不愿意这么做,因为如果他愿意的话,你也不会看到这篇文章了…
在这里插入图片描述

方案二:后端返回接口时过滤掉值为null的字段,前端拿到数据后做个 跟本地初始化的数据做一个merge 的操作

方案一对于后端来讲可能会比较麻烦,过滤掉值为null的字段再把数据给你对他们来讲还是比较简单的,基本上全局配置下就行了。以.net 为例,只需要几行代码配置下即可。
在这里插入图片描述
这样一来,假如原本返回给你的数据是:

{
    "baseInfo": {
        "name": null,
        "age": 27,
        "hobby": [
            "吃",
            "喝",
            "玩",
            "乐"
        ]
    },
    "bankCard": [
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国农业银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "信用卡"
        }
    ]
}

那么过滤后返回的数据就是这样的:

{
    "baseInfo": {
        "age": 27,
        "hobby": [
            "吃",
            "喝",
            "玩",
            "乐"
        ]
    },
    "bankCard": [
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国农业银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "借记卡"
        },
        {
            "no": "6228482398431xxxxxx",
            "bankName": "中国银行",
            "type": "信用卡"
        }
    ]
}

过滤后就不会返回给你name这个字段了,我们拿到数据后跟本地初始化好的数据进行一次merge操作即可。
这里要注意的是 merge 不是简单的数据浅拷贝。

类似于 Object.assign() 这种方法是肯定不行的,因为他是浅拷贝,会出现数据直接被覆盖的情况。

这里给大家推荐个开源库 Lodash

Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库,提供了很多方法供我们调用,里面有个 对象的merge 方法,正好是我们所需要的。

使用起来非常简单,直接看文档即可。
大致用法如下:


  	/*本地初始化的数据*/
 	person:Person=new Person()

    /*合并数据*/
    Lodash.merge(this.person,apiValue)

执行后结果如下:
在这里插入图片描述

这样一来我们就无需再写这么多恶心的字段值校验代码了,美滋滋啊。

关于如何在Angular中如何使用lodash请看 Angular中使用Lodash 这篇文章,里面有详细的步骤以及示例效果。

什么!!! 过滤null值后台也不愿意做?
那不好意思,建议你俩PK一下…

在这里插入图片描述

唉~ 先放下手中的键盘,别着急,不要慌,问题不大,都是打工人,相煎何太急啊…

来看下方案二加强版

方案二加强版:无需后端做任何操作,该怎么返回就怎么返回,前端直接Merge,Merge的时候处理一下null值

有了这个方法,你就不用去 “求” 后台帮你做处理了,直接告诉他,你随便怎么返回吧,我这都ok…

相信看过Lodash文档的同学已经发现了 Lodash中 mergeWith
这个方法了。

这个方法允许我们自定义合并的规则,我们可以这样定义,如果接口给的值是null,我们就拿默认值,否则,就以接口给的值为准。

代码如下:

     Lodash.mergeWith(this.person,apiValue,(localData,apiData)=>
       apiData===null?localData:undefined
    )

这样写的话,就算接口返回给你的数据字段值为null,哪怕少返回了字段,我们也可以处理成本地的初始值,再也不用写那些恶心的值校验代码了,还能提升不少编码效率。

好了,以上就是本篇博客的内容了,希望能帮到你。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页