利用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 相关文章推荐
{}与function(){}选用空对象{}来存放keyValue
May 23 Javascript
JS字符串处理实例代码
Aug 05 Javascript
web网页按比例显示图片实现原理及js代码
Aug 09 Javascript
Javascript基础教程之break和continue语句
Jan 18 Javascript
浅谈angularJS 作用域
Jul 05 Javascript
详解Webwork中Action 调用的方法
Feb 02 Javascript
js判断数组是否包含某个字符串变量的实例
Nov 24 Javascript
浅谈Vue2.0中v-for迭代语法的变化(key、index)
Mar 06 Javascript
vue+element表格导出为Excel文件
Sep 26 Javascript
Vue实现开心消消乐游戏算法
Oct 22 Javascript
vue.js循环radio的实例
Nov 07 Javascript
微信小程序图片自适应实现解析
Jan 21 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正则匹配汉字的方法介绍
2013/04/25 PHP
php中socket的用法详解
2014/10/24 PHP
jquery 弹出登录窗口实现代码
2009/12/24 Javascript
js 实现图片预加载(js操作 Image对象属性complete ,事件onload 异步加载图片)
2011/03/25 Javascript
ASP.NET jQuery 实例13 原创jQuery文本框字符限制插件-TextArea Counter
2012/02/03 Javascript
Javascript 异步加载详解(浏览器在javascript的加载方式)
2012/05/20 Javascript
基于jQuery实现文本框缩放以及上下移动功能
2014/11/24 Javascript
JS实现单击输入框弹出选择框效果完整实例
2015/12/14 Javascript
微信js-sdk预览图片接口及从拍照或手机相册中选图接口用法示例
2016/10/13 Javascript
轻松理解JavaScript之AJAX
2017/03/15 Javascript
dropload.js插件下拉刷新和上拉加载使用详解
2017/10/20 Javascript
你应该了解的JavaScript Array.map()五种用途小结
2018/11/14 Javascript
Layui实现主窗口和Iframe层参数传递
2019/11/14 Javascript
详细分析Node.js 多进程
2020/06/22 Javascript
vscode+gulp轻松开发小程序的完整步骤
2020/10/18 Javascript
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
使用python开发vim插件及心得分享
2014/11/04 Python
Python实现查找系统盘中需要找的字符
2015/07/14 Python
python与php实现分割文件代码
2017/03/06 Python
python+matplotlib实现礼盒柱状图实例代码
2018/01/16 Python
pygame游戏之旅 python和pygame安装教程
2018/11/20 Python
Jupyter notebook无法导入第三方模块的解决方式
2020/04/15 Python
详解如何在css3打包后自动追加前缀插件:autoprefixer
2018/12/18 HTML / CSS
基于HTML5 Canvas:字符串,路径,背景,图片的详解
2013/05/09 HTML / CSS
世界上最大的艺术和工艺用品商店:MisterArt.com
2018/07/13 全球购物
IFCHIC台湾:欧美国际设计师品牌
2019/05/18 全球购物
EJB的角色和三个对象
2015/12/31 面试题
个人应聘自我评价分享
2013/11/18 职场文书
求职信怎么写
2014/05/23 职场文书
大学生学雷锋活动总结
2014/06/26 职场文书
社区活动策划方案
2014/08/21 职场文书
2014年小学体育工作总结
2014/12/11 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
Nginx本地目录映射实现代码实例
2021/03/31 Servers
python实现剪贴板的操作
2021/07/01 Python
MySQL数据库之存储过程 procedure
2022/06/16 MySQL