利用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 相关文章推荐
html下载本地
Jun 19 Javascript
jQuery 淡入淡出 png图在ie8下有黑色边框的解决方法
Mar 05 Javascript
js判断undefined变量类型使用typeof
Jun 03 Javascript
jquery判断密码强度的验证代码
Apr 22 Javascript
浅谈jquery.form.js的ajaxSubmit和ajaxForm的使用
Sep 09 Javascript
原生js更改css样式的两种方式
Mar 15 Javascript
jQuery中table数据的值拷贝和拆分
Mar 19 Javascript
基于vue2的table分页组件实现方法
Mar 20 Javascript
webpack构建vue项目的详细教程(配置篇)
Jul 17 Javascript
javascript 模块依赖管理的本质深入详解
Apr 30 Javascript
使用JavaScript获取Django模板指定键值数据
May 27 Javascript
vue实现路由懒加载的3种方法示例
Sep 01 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
解析thinkphp中的M()与D()方法的区别
2013/06/22 PHP
PHP+javascript制作带提示的验证码源码分享
2014/05/28 PHP
PHP大批量插入数据库的3种方法和速度对比
2014/07/08 PHP
php cookie工作原理与实例详解
2016/07/18 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
2018/09/28 PHP
Referer原理与图片防盗链实现方法详解
2019/07/03 PHP
让网页根据不同IE版本显示不同的内容
2009/02/08 Javascript
基于Jquery的动态添加控件并取值的实现代码
2010/09/24 Javascript
php显示当前文件所在的文件以及文件夹所有文件以树形展开
2013/12/13 Javascript
node.js解决获取图片真实文件类型的问题
2014/12/20 Javascript
JavaScript中的值类型转换介绍
2014/12/31 Javascript
javascript与jquery中的this关键字用法实例分析
2015/12/24 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
2016/09/06 Javascript
微信小程序 开发指南详解
2016/09/27 Javascript
利用JS轻松实现获取表单数据
2016/12/06 Javascript
原生JS实现瀑布流插件
2018/02/06 Javascript
angularJs提交文本框数据到后台的方法
2018/10/08 Javascript
重学JS之显示强制类型转换详解
2019/06/30 Javascript
Ant Design Vue 添加区分中英文的长度校验功能
2020/01/21 Javascript
antd table按表格里的日期去排序操作
2020/11/17 Javascript
pandas 两列时间相减换算为秒的方法
2018/04/20 Python
python 拷贝特定后缀名文件,并保留原始目录结构的实例
2018/04/27 Python
Django+uni-app实现数据通信中的请求跨域的示例代码
2019/10/12 Python
python mysql自增字段AUTO_INCREMENT值的修改方式
2020/05/18 Python
Python常驻任务实现接收外界参数代码解析
2020/07/21 Python
python绘制趋势图的示例
2020/09/17 Python
非常震撼的纯CSS3人物行走动画
2016/02/24 HTML / CSS
铭宣海淘转运:美国、日本、英国转运等全球转运公司
2019/09/10 全球购物
Java语言的优势
2015/01/10 面试题
北京捷通华声语音技术有限公司Java软件工程师笔试题
2012/04/10 面试题
《难忘的泼水节》教学反思
2014/02/27 职场文书
电子商务专业应届生求职信
2014/05/28 职场文书
群众路线教育党员自我剖析材料
2014/10/06 职场文书
董事长助理岗位职责
2015/02/11 职场文书
2016年学校禁毒宣传活动工作总结
2016/04/05 职场文书
详解Vue中$props、$attrs和$listeners的使用方法
2022/02/18 Vue.js