利用prop-types第三方库对组件的props中的变量进行类型检测


Posted in Javascript onMay 02, 2017

1.引言——JavaScript就是一个熊孩子

1.1对于JSer们来说,js是自由的,但同时又有许多让人烦恼的地方。javascript很多时候就是这么一个熊孩子,他很多时候并不会像C和java这些“好孩子”那样循规蹈矩。因此给我们带来许多烦恼

<1>运行时候控制台报错:uncaught error,这尤其令人恼火的是系统告诉我们有错误但是又不告诉我们错误发生在哪里。试想一下,你到一个地方旅游迷了路,一个当地的熊孩子一直笑嘻嘻地跟在你后头告诉你:“你走错啦!”。但是不告诉你应该怎么走,你会不会很想揍他一顿?(? ̄皿 ̄)

<2>运行时报了确定的错误,然而我们发现这TM完全是一条驴唇不对马嘴的错误报告。甚至于去stackoverflow上寻找答案,却发现提问的错误场景跟自己的根本是两码事。让我们回到1中场景,假如这个熊孩子很好心地告诉了你路线,结果你走到天黑发现被熊孩子狠狠得耍了,导致你不得不在大晚上露宿街头,你会不会比1中场景更想揍他一顿?(? ̄皿 ̄) 

<3>你主观地写错了了一个变量的类型,比如把字符串1写成数字1,但是系统“很好心”地不报错误提示。(我们都不需要特别的进行类型声明当然不会报告错误提示啦)而这却可能就是你接下来bug的源头。让我们回到1,2中场景,假如这个熊孩子知道你这个外地人绝逼是走错路了,但当你问路:“我走对路了吗?”时候,他笑靥如花满面春风得点点头,让你充满信心充满希望得一条路走到黑。我想你此时的心情不会比1和2中的要好(? ̄皿 ̄)

<2>中情况有时候比较难以避免

<1>中情况我们可以通过熟悉主要的6种uncaught error的情形加以判断。(在下一篇文章里我会讨论这个问题)

<3>中的情况呢,完全可以用类型检测的方式加以避免,这也就是我这篇文章所讲到的内容

本节主要讨论的是与react配套的类型检测库——prop-types的运用

今天我在这篇文章里面介绍的内容,就是通过react的propTypes进行类型检测,。顾名思义prop-types就是对react组件中props对象中的变量进行类型检测的,因为props是react数据流的管道,我们通过prop-types就可以轻松监控react里大多数据的变量类型先介绍下propTypes的基本用法。

2.prop-types基础入门

2.1首先你需要通过在终端npm install prop-types安装一个叫prop-types的第三方包

2.2然后通过下面的写法对你的某一个组件的props中的变量进行类型检测:

yourComponent.propTypes = {
  属性1:属性1的变量类型,
  属性2:属性2的变量类型
  //...
}

3.propTypes的使用全解

3.1利用propTypes检测全部数据类型的变量

import React from 'react'
 class Son extends React.Component{
 render(){
 return (<div style ={{padding:30}}>
    {this.props.number}
    <br/>
    {this.props.array}
    <br/>
    {this.props.boolean.toString()}
   </div>)
   }
}
class Father extends React.Component{
 render(){
  return (<Son
    number = {'1'}
    array = {'[1,2,3]'}
    boolean = {'true'}
    />)
   }
}

比如这个例子,我们通过props从父组件向子组件传递属性,你原本试图通过number,array和boolean这三个属性分别向Son中传递一个数字,数组和一个布尔型数值,但由于你过度疲惫,把它们都写成了字符串,虽然渲染是正常的,但这可能会导致你接下来调用一些方法的时候发生错误,而系统并不提供任何提示。

利用prop-types第三方库对组件的props中的变量进行类型检测

利用prop-types第三方库对组件的props中的变量进行类型检测

让我们给它加上propTypes的类型检测:

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
 render(){
  return (<div style ={{padding:30}}>
      {this.props.number}
      <br/>
      {this.props.array}
      <br/>
      {this.props.boolean.toString()}
     </div>)
     }
}
Son.propTypes = {
  number:PropTypes.number,
  array:PropTypes.array,
  boolean:PropTypes.bool
}
class Father extends React.Component{
 render(){
   return (<Son
      number = {'1'}
      array = {'[1,2,3]'}
      boolean = {'true'}
      />)
     }
}

然后我们就能看到报的错误了,而且这个时候,报的错误包括错误的props属性名称,错误的变量类型,属性所在的组件名称,预期的正确的变量类型,错误代码的位置以及其他更详细的信息。

这种“人为控制”的报错比一般的系统报错看起来应该要亲切自然得多吧...你大可以说:这个error是我“私人定制”的呦 (//?//)

利用prop-types第三方库对组件的props中的变量进行类型检测

propTypes 能用来检测全部数据类型的变量,包括基本类型的的string,boolean,number,以及引用类型的object,array,function,甚至还有ES6新增的symbol类型

Son.propTypes = {
  optionalArray: PropTypes.array,//检测数组类型
  optionalBool: PropTypes.bool,//检测布尔类型
  optionalFunc: PropTypes.func,//检测函数(Function类型)
  optionalNumber: PropTypes.number,//检测数字
  optionalObject: PropTypes.object,//检测对象
  optionalString: PropTypes.string,//检测字符串
  optionalSymbol: PropTypes.symbol,//ES6新增的symbol类型
}

【注意】下面这些是从官方英文文档里引用过来的,你大概能够注意到,五种基本类型中的undefined和null并不在此列,propTypes类型检测的缺憾之一是,对于undefined和null的值,它无法捕捉错误

让我们把上述实例中的Father组件传递给Son组件修改一下,改成:

class Father extends React.Component{
 render(){
  return (<Son
     number = {null}
     array = {null}
     boolean = {null}
    />)
    }
}

结果是输出台不报任何错误,(当然你改成undefined也是同样效果)。 

利用prop-types第三方库对组件的props中的变量进行类型检测

3.2 通过oneOfType实现多选择检测——可规定多个检测通过的数据类型

上个例子中类型检测的要求是一个变量对应一个数据类型,也就是规定的变量类型只有一个。那么怎样能让它变得灵活一些,比如规定多个可选的数据类型都为检测通过呢?PropTypes里的oneOfType方法可以做到这一点,oneOfType方法接收参数的是一个数组,数组元素是你希望检测通过的数据类型。

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
 render(){
  return (<div style ={{padding:30}}>
     {this.props.number}
     </div>)
    }
}
Son.propTypes = {
  number:PropTypes.oneOfType(
   [PropTypes.string,PropTypes.number]
   )
}
class Father extends React.Component{
 render(){
   //分别渲染数字的11和字符串的11
  return (<div>
      <Son number = {'字符串11'}/>
      <Son number = {11}/>
     </div>)
    }
}

这时候,因为在类型检测中,number属性的规定类型包括字符串和数字两种,所以此时控制台无报错

利用prop-types第三方库对组件的props中的变量进行类型检测

当然,如果你改为number = {数组或其他类型的变量},那么这时就会报错了

利用prop-types第三方库对组件的props中的变量进行类型检测

3.3 通过oneOf实现多选择检测——可规定多个检测通过的变量的值

3.2是规定了多个可检测通过的数据类型,那么同样的道理,我们也可以规定多个可检测通过的变量的值,这就要用到PropTypes里的oneOf方法,和PropTypes方法一样oneOf方法接收参数的是一个数组,数组元素是你希望检测通过的变量的值,比如我们把上面类型检测的部分改成:

Son.propTypes = {
  number:PropTypes.oneOf(
     [12,13]
   )
}

那么运行时就会报这样一段错误:

利用prop-types第三方库对组件的props中的变量进行类型检测

3.4 arrayOf,objectOf实现多重嵌套检测

试想一下,如果我们检测的是基本类型的变量,那么这自然是很简单的,但当我们要检测的是一个引用类型的变量呢?当我们除了检测这个变量是否符合规定的引用类型外(Object/array),还想要进一步检测object中的属性变量或array中数组元素的数据类型时,单靠上面的方法已经不能满足要求了。这时候就要用到PropTypes的arrayOf,objectOf方法。

arrayOf接收一个参数,这个参数是规定的数组元素的数据类型。objectOf接收的参数则是属性的数据类型

我们对上述例子做些修改:

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
 render(){
  return (<div style ={{padding:30}}>
    {this.props.array}
    </div>)
   }
}
Son.propTypes = {
  array:PropTypes.arrayOf(PropTypes.number)
}
class Father extends React.Component{
 render(){
  return (<div>
     <Son array = {[1,2,3,4]}/>
    </div>)
}
}

正常渲染,然后我们把<Son array = {[1,2,3,4]}/>改为<Son array = {['1','2','3','4']}/>,报错

利用prop-types第三方库对组件的props中的变量进行类型检测

【注意】虽然报错但是这并不会影响程序的正常运行(譬如上面我们看到渲染仍然是正常的),因为本质上说类型检测报的是非致命性错误warning而不是致命性错误error(区别在于是否影响了正常运行)。对objectOf也是同样的做法

3.5 通过shape方法检测目标对象不同属性的不同数据类型

如果你认真思考一下的话,你会发现3.4中的objectOf有一个缺陷,就是它内部的属性的数据类型被强行规定为一种,但通常一个对象里应该是有多种不同类型的属性了,那么这时候objectOf就不符合要求了,我们应该使用shape方法,其用法:

PropTypes.shape({
 属性1:类型1,
 属性2:类型2,
 //...
}),

举个例子:

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
  render(){
  return (<div style ={{padding:30}}>
     {'我的名字叫' + this.props.object.name}
     <br/>
     {'我的年龄是' + this.props.object.age}
     </div>)
    }
}
Son.propTypes = {
  object:PropTypes.shape({
  name:PropTypes.string,
  age:PropTypes.number
  })
}
class Father extends React.Component{
 render(){
  return (<div>
     <Son object = {{name:'彭湖湾',age:20}}/>
    </div>)
  }
}

无报错,把<Son object = {{name:'彭湖湾',age:20}}/>改成<Son object = {{name:'彭湖湾',age:'20'}}/>,然后就能喜闻乐见得报错了

利用prop-types第三方库对组件的props中的变量进行类型检测

3.6 通过isRequired检测props中某个必要的属性(如果该属性不存在就报错)

有时候,我们在对某个变量进行类型检测时,我们不仅要求它符合预期的类型,同时也要求它是必须写入的,这时候就要用到isRequired。

【分析】

Son.propTypes = {
   number:PropTypes.number
}

这段代码的作用是当你在props中写入number属性且number属性类型错误时给予报错提示,可如果你压根就没有写入number属性呢?没错,什么错误都不会报。这就是使用isRequired的必要性

【栗子】

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
 render(){
  return (<div style ={{padding:30}}>
     {this.props.number}
    </div>)
   }
}
Son.propTypes = {
  number:PropTypes.number
}
class Father extends React.Component{
 render(){
  return (<div>
    <Son />
    </div>)
  }
}

控制台无任何输出

利用prop-types第三方库对组件的props中的变量进行类型检测

如果我们改成:

Son.propTypes = {
 number:PropTypes.number.isRequired
}

再运行,我们就又可以喜闻乐见得看到错误了:

利用prop-types第三方库对组件的props中的变量进行类型检测

【注意】在这里给大家提个问题:我们上述的写法是number:PropTypes.number.isRequired,这要求number是数字类型,但如果你不想控制number的类型而仅仅是想控制它的必要性呢?难道写成number:isRequired或number:PropTypes.isRequired? 这个时候PropTypes.any就登场啦!它代表了该变量可取任何一种数据类型,所以你可以写成这样——number: PropTypes.any.isRequired

3.7 应对更复杂的类型检测——将PropTypes的属性值写成函数

Son.propTypes = {
  prop:function(props,propName,componentName){
   if(/*判断条件*/){
    return new Error(/*错误的参数*/)
   }
 }
}

在属性prop的类型检测中,属性值是一个函数,在这里props是包含prop的props对象,propName是prop的属性名,componentName是props所在的组件名称,函数的返回值是一个Error对象

import React from 'react'
import PropTypes from 'prop-types';
class Son extends React.Component{
   render(){
    return (<div style ={{padding:30}}>
      {this.props.email}
      </div>)
     }
}
Son.propTypes = {
  email:function(props,propName,componentName){
   if(!/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(props[propName])){
     return new Error('组件' + componentName+ '里的属性' + propName + '不符合邮箱的格式');
       }
    }
}
class Father extends React.Component{
  render(){
    return (<div>
      <Son email = {2314838004}/>
      </div>)
    }
}

在这里我们利用正则表达式检测传递到Son组件的email属性是否符合邮箱格式,如果不符合就抛出错误,那么2314838004显然不符合这一要求,所以我们就得到下面的demo:(其实加上qq.com就是我的邮箱啦 哈哈)

利用prop-types第三方库对组件的props中的变量进行类型检测

4.ES7下类型检测的新写法:

可能你觉得把propTypes写在类外看起来有些怪怪的,在ES7的静态类属性的支持下,你可以这样写:

class Son extends React.Component{
static propTypes = {
  //..类型检测
}
render(){
 return (/* 渲染*/)
  }
}

但注意,这在ES7下生效

5.props-types的独立与react.PropTypes的弃用

在上面我是利用props-types这个独立的第三方库来进行类型检测的,但在不久前(react V15.5以前),它使用的是react内置的类型检测,而不是第三方库(也就是说我们现在的prop-types是当初以react内置的PropTypes对象为基础分离出来的)

利用prop-types第三方库对组件的props中的变量进行类型检测

翻译成中文就是:

利用prop-types第三方库对组件的props中的变量进行类型检测

所以说在你也可以这样进行类型检测,虽然并不推荐(为了保持向下兼容这在最新版本的react上仍然是可用的)

Son.propTypes = {
 number:React.PropTypes.number
}

6.参考资料:

react官方文档/高级指导/类型检测(docs/advanced guide/Typechecking with propTypes)

https://facebook.github.io/react/docs/typechecking-with-proptypes.html

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript 实现??打印?理
Apr 28 Javascript
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
Apr 07 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
Aug 04 Javascript
JavaScript iframe数据共享接口实现方法
Jan 06 Javascript
jQuery CSS3自定义美化Checkbox实现代码
May 12 Javascript
Node.js websocket使用socket.io库实现实时聊天室
Feb 20 Javascript
你有必要知道的10个JavaScript难点
Jul 25 Javascript
nginx+vue.js实现前后端分离的示例代码
Feb 12 Javascript
使用nvm和nrm优化node.js工作流的方法
Jan 17 Javascript
Vue 实现点击空白处隐藏某节点的三种方式(指令、普通、遮罩)
Oct 23 Javascript
vant 时间选择器--开始时间和结束时间实例
Nov 04 Javascript
ES6 十大特性简介
Dec 09 Javascript
xmlplus组件设计系列之路由(ViewStack)(7)
May 02 #Javascript
JavaScript比较两个数组的内容是否相同(推荐)
May 02 #Javascript
xmlplus组件设计系列之分隔框(DividedBox)(8)
May 02 #Javascript
xmlplus组件设计系列之树(Tree)(9)
May 02 #Javascript
详解Vue2.X的路由管理记录之 钩子函数(切割流水线)
May 02 #Javascript
令按钮悬浮在(手机)页面底部的实现方法
May 02 #Javascript
Vue2.0表单校验组件vee-validate的使用详解
May 02 #Javascript
You might like
php curl常见错误:SSL错误、bool(false)
2011/12/28 PHP
PHP MYSQL实现登陆和模糊查询两大功能
2016/02/05 PHP
thinkPHP框架实现的短信接口验证码功能示例
2018/06/20 PHP
Javascript &amp; DHTML 实例编程(教程)基础知识
2007/06/02 Javascript
用jquery ajax获取网站Alexa排名的代码
2009/12/12 Javascript
火狐下table中创建form导致两个table之间出现空白
2013/09/02 Javascript
Javascript基础教程之switch语句
2015/01/18 Javascript
angularJS中router的使用指南
2015/02/09 Javascript
js兼容pc端浏览器并有多种弹出小提示的手机端浮层控件实例
2015/04/29 Javascript
javascript省市级联功能实现方法实例详解
2015/10/20 Javascript
jQuery基于$.ajax设置移动端click超时处理方法
2016/05/14 Javascript
jQuery实现立体式数字动态增加(animate方法)
2016/12/21 Javascript
jQuery.parseHTML() 函数详解
2017/01/09 Javascript
基于react框架使用的一些细节要点的思考
2017/05/31 Javascript
webpack4 optimization使用总结
2019/11/10 Javascript
vue项目中锚点定位替代方式
2019/11/13 Javascript
解决echarts数据二次渲染不成功的问题
2020/07/20 Javascript
如何准确判断请求是搜索引擎爬虫(蜘蛛)发出的请求
2015/10/13 Python
python2.7实现FTP文件下载功能
2018/04/15 Python
解决Python下json.loads()中文字符出错的问题
2018/12/19 Python
在Python中字典按值排序的实现方法
2020/11/12 Python
Python 实现PS滤镜中的径向模糊特效
2020/12/03 Python
通过python-pptx模块操作ppt文件的方法
2020/12/26 Python
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
StubHub中国:购买和出售全球活动门票
2020/01/01 全球购物
如何估计一张表的大小(假设该表中有1万条数据)
2016/03/27 面试题
利达恒信公司.NET笔试题面试题
2016/03/05 面试题
小学生安全保证书
2014/02/01 职场文书
大学四年个人自我小结
2014/03/05 职场文书
自考毕业自我鉴定
2014/03/18 职场文书
法定代表人授权委托书范文
2014/08/02 职场文书
药店采购员岗位职责
2014/09/30 职场文书
创先争优承诺书
2015/01/20 职场文书
给老婆的道歉信
2015/01/20 职场文书
小学生五一劳动节演讲稿
2015/03/18 职场文书
惊涛骇浪观后感
2015/06/05 职场文书