利用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 相关文章推荐
js 深拷贝函数
Dec 04 Javascript
超轻量级的基于jquery的三级展开列表
Apr 26 Javascript
jquery.artwl.thickbox.js  一个非常简单好用的jQuery弹出层插件
Mar 01 Javascript
jquery聚焦文本框与扩展文本框聚焦方法
Oct 12 Javascript
jqueyr判断checkbox组的选中(示例代码)
Nov 08 Javascript
node.js中的fs.symlinkSync方法使用说明
Dec 15 Javascript
浅谈Node.js中的定时器
Jun 18 Javascript
详解vue 实例方法和数据
Oct 23 Javascript
编写React组件项目实践分析
Mar 04 Javascript
vue-router传递参数的几种方式实例详解
Nov 13 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
Dec 24 Javascript
ckeditor一键排版功能实现方法分析
Feb 06 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
收音机另类DIY - 纸巾盒做外壳
2021/03/02 无线电
php生成文件
2007/01/15 PHP
php中多维数组按指定value排序的实现代码
2014/08/19 PHP
启用Csrf后POST数据时出现的400错误
2015/07/05 PHP
PHP PDOStatement::bindParam讲解
2019/01/30 PHP
PHP中16个高危函数整理
2019/09/19 PHP
js 与或运算符 || &amp;&amp; 妙用
2009/12/09 Javascript
jquery监控数据是否变化(修正版)
2011/04/12 Javascript
js获取单选框或复选框值及操作
2012/12/18 Javascript
解析Node.js基于模块和包的代码部署方式
2016/02/16 Javascript
Bootstrap幻灯片轮播图支持触屏左右手势滑动的实现方法
2016/10/13 Javascript
Vue学习笔记进阶篇之多元素及多组件过渡
2017/07/19 Javascript
自定义Vue组件打包、发布到npm及使用教程
2019/05/22 Javascript
Layui点击图片弹框预览的实现方法
2019/09/16 Javascript
Vue的双向数据绑定实现原理解析
2020/02/17 Javascript
JavaScript实现图片伪异步上传过程解析
2020/04/10 Javascript
python复制文件代码实现
2013/12/23 Python
Win7上搭建Cocos2d-x 3.1.1开发环境
2014/07/03 Python
浅谈Python处理PDF的方法
2017/11/10 Python
python XlsxWriter模块创建aexcel表格的实例讲解
2018/05/03 Python
pandas求两个表格不相交的集合方法
2018/12/08 Python
Django JWT Token RestfulAPI用户认证详解
2019/01/23 Python
python write无法写入文件的解决方法
2019/01/23 Python
Python使用PyQt5/PySide2编写一个极简的音乐播放器功能
2020/02/07 Python
python异常处理之try finally不报错的原因
2020/05/18 Python
Python参数传递对象的引用原理解析
2020/05/22 Python
python中entry用法讲解
2020/12/04 Python
python字典与json转换的方法总结
2020/12/28 Python
美国最灵活的移动提供商:Tello
2017/07/18 全球购物
MSC邮轮官方网站:加勒比海、地中海和世界各地的假期
2018/08/27 全球购物
幼师自我鉴定
2014/02/01 职场文书
小学生安全演讲稿
2014/04/25 职场文书
保险公司开门红口号
2014/06/21 职场文书
农村环境卫生倡议书
2015/04/29 职场文书
2016简单的租房合同范本
2016/03/18 职场文书
深入详解JS函数的柯里化
2021/06/09 Javascript