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

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中传递一个数字,数组和一个布尔型数值,但由于你过度疲惫,把它们都写成了字符串,虽然渲染是正常的,但这可能会导致你接下来调用一些方法的时候发生错误,而系统并不提供任何提示。

让我们给它加上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是我“私人定制”的呦 (//▽//)

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也是同样效果)。

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属性的规定类型包括字符串和数字两种,所以此时控制台无报错

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

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

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

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

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

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']}/>,报错

【注意】虽然报错但是这并不会影响程序的正常运行(譬如上面我们看到渲染仍然是正常的),因为本质上说类型检测报的是非致命性错误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'}}/>,然后就能喜闻乐见得报错了

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>)
  }
}

控制台无任何输出

如果我们改成:

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

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

【注意】在这里给大家提个问题:我们上述的写法是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就是我的邮箱啦 哈哈)

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对象为基础分离出来的)

翻译成中文就是:

所以说在你也可以这样进行类型检测,虽然并不推荐(为了保持向下兼容这在最新版本的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

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

(0)

相关推荐

  • Vuejs 组件——props数据传递的实例代码

    本篇资料来于官方文档:http://cn.vuejs.org/guide/components.html#Props 本文是在官方文档的基础上,更加细致的说明,代码更多更全. 简单来说,更适合新手阅读 props数据传递 ①组件实例的作用域: 是孤立的,简单的来说,组件和组件之间,即使有同名属性,值也不共享. <div id="app"> <add></add> <del></del> </div> <scr

  • Vuejs第九篇之组件作用域及props数据传递实例详解

    本篇资料来于官方文档: http://cn.vuejs.org/guide/components.html#Props 本教程是小编结合官方文档整理的一套更加细致,代码更多更全的教程,特别适合新手阅读. props数据传递 ①组件实例的作用域: 是孤立的,简单的来说,组件和组件之间,即使有同名属性,值也不共享. <div id="app"> <add></add> <del></del> </div> <sc

  • 详解如何在Vue2中实现组件props双向绑定

    Vue学习笔记-3 前言 Vue 2.x相比较Vue 1.x而言,升级变化除了实现了Virtual-Dom以外,给使用者最大不适就是移除的组件的props的双向绑定功能. 以往在Vue1.x中利用props的twoWay和.sync绑定修饰符就可以实现props的双向绑定功能,但是在Vue2中彻底废弃了此功能,如果需要双向绑定需要自己来实现. Vue2的组件props通信方式 在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribu

  • Vue2实现组件props双向绑定

    Vue学习笔记-3 前言 Vue 2.x相比较Vue 1.x而言,升级变化除了实现了Virtual-Dom以外,给使用者最大不适就是移除的组件的props的双向绑定功能. 以往在Vue1.x中利用props的twoWay和.sync绑定修饰符就可以实现props的双向绑定功能,但是在Vue2中彻底废弃了此功能,如果需要双向绑定需要自己来实现. Vue2的组件props通信方式 在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribu

  • vue的props实现子组件随父组件一起变化

    本文实例为大家分享了vue的props实现父组件变化子组件一起变化,供大家参考,具体内容如下 类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 绑定动态 Props 到父组件的数据.每当父组件的数据变化时,也会传导给子组件: <div> <input v-model="parentMsg"> <br> <child v-bind:my-message="parentMsg"></c

  • Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案

    在项目中开始使用vue2来构建项目了,跟 vue1 很大的一处不同在于2 取消了props 的双向绑定,改成只能从父级传到子级的单向数据流,初衷当然是好的,为了避免双向绑定在项目中容易造成的数据混乱. 解决方案一 然后开始参考网上和github上的方案等等,发现很多解决方案是这样的 用data对象中创建一个props属性的副本 watch props属性 赋予data副本 来同步组件外对props的修改 watch data副本,emit一个函数 通知到组件外 这里以最常见的 modal为例子:

  • 简单理解vue中Props属性

    本文实例为大家解析了vue中Props的属性,供大家参考,具体内容如下 使用 Props 传递数据 组件实例的作用域是孤立的.这意味着不能并且不应该在子组件的模板内直接引用父组件的数据.可以使用 props 把数据传给子组件. "prop" 是组件数据的一个字段,期望从父组件传下来.子组件需要显式地用 props 选项 声明 props: Vue.component('child', { // 声明 props props: ['msg'], // prop 可以用在模板内 // 可以

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

    1.引言--JavaScript就是一个熊孩子 1.1对于JSer们来说,js是自由的,但同时又有许多让人烦恼的地方.javascript很多时候就是这么一个熊孩子,他很多时候并不会像C和java这些"好孩子"那样循规蹈矩.因此给我们带来许多烦恼 <1>运行时候控制台报错:uncaught error,这尤其令人恼火的是系统告诉我们有错误但是又不告诉我们错误发生在哪里.试想一下,你到一个地方旅游迷了路,一个当地的熊孩子一直笑嘻嘻地跟在你后头告诉你:"你走错啦!&q

  • Vue 子组件更新props中的属性值问题

    目录 Vue子组件更新props的属性值 .sync属性 v-model应用 Vue子组件中修改Props的几种情况 针对以上几种情况再逐一进行分析 结果展示 结论 Vue子组件更新props的属性值 在子组件中更新props中的属性值,并且更新到父组件,有两种实现方式:.sync 和 自定义v-model .sync属性 父组件在给子组件传值时,属性名后需要加修饰符.sync,格式 :子组件props属性名.sync 父组件 <template> <div id="app&q

  • vue实现移动端轻量日期组件不依赖第三方库的方法

    不需要依赖第三方组件的vue日期移动端组件  小轮子 轻量可复用:   https://github.com/BeckReed/datepicker-for-vue 2.用法:参见 src/view/demo.vue 文件的用法,简单易懂 <div> <h3>三列(年月日)日期弹窗示例--带标题)</h3> <button class="blue-btn" @click="togglePicker2">显示三列带标题日

  • 利用Python第三方库xlwt写入数据到Excel工作表实例代码

    目录 1. 安装 xlwt 库 2. 使用 xlwt 库 2.1 向 Excel 工作表写入单个数据 2.2 向 Excel 工作表写入多个数据 2.3 向 Excel 工作表写入多个数据(进阶) 3. 总结 1. 安装 xlwt 库 Python 写入数据到 Excel 工作簿中可以使用第三方库 xlwt. xlwt 拆分下来看就是 excel 和 write 的简化拼接,意思就是写数据到 Excel. 这个第三方库的 pip 安装命令如下所示: pip install xlwt -i htt

  • 利用Python第三方库xlrd读取Excel中数据实例代码

    目录 1. 安装 xlrd 库 2. 使用 xlrd 库 2.1 打开 Excel 工作表对象 2.2 读取单个单元格数据 2.3 读取多个单元格数据 2.3 读取所有单元格数据 附:行.列操作 3. 总结 1. 安装 xlrd 库 Python 读取 Excel 中的数据主要用到 xlrd 第三方库.xlrd 其实就是两个单词的简化拼接,我们可以把它拆开来看,xl 代表 excel, rd 代表 read, 合并起来就是 xlrd, 意思就是读 excel 的第三方库. 这种命名风格也正是我们

  • Python标准库与第三方库详解

    本文详细罗列并说明了Python的标准库与第三方库如下,供对此有需要的朋友进行参考: Tkinter---- Python默认的图形界面接口. Tkinter是一个和Tk接口的模块,Tkinter库提供了对Tk API的接口,它属于Tcl/Tk的GUI工具组.Tcl/Tk是由John Ousterhout发展的书写和图形设备.Tcl(工具命令语言)是个宏语言,用于简化shell下复杂程序的开发,Tk工具包是和Tcl一起开发的, 目的是为了简化用户接口的设计过程.Tk工具包由许多不同的小部件,如一

  • Angular 如何使用第三方库的方法

    Angular 的组件与模块看似好像与现有各种第三方类库(例如:lodash.moment 等)使用上有点格格不入,这很大的原因是 TypeScript 造成的假象.三足鼎立的前端其实都是雷同的,不管是哪种前端框架都可以使用到这些第三方类库. 以下我将从另一个视角解释 Angular 如何使用第三方类库的一种经验做法. 一.写在前面 在开始之前,需要先了解一下 TypeScript 模块系统 --模块是指在其自身作用域里执行,而不是在全局作用域里:模块间是依靠 export 和 import 建

  • 2020年10款优秀的Python第三方库,看看有你中意的吗?

    相对于numpy.TensorFlow.pandas这些已经经过多年维护.迭代,对于大多数Python开发者耳熟能详的库不同. 今天要给大家介绍的是诞生于2020年的新鲜Python库,而且,本文介绍的这10个Python库一直都受到非常好的维护. 废话不多说,下面开始本文的正式内容! 1. Typer 或许,你并非经常编写 CLI 应用程序,但是当你编写时,有可能会遇到很多障碍. 继FastAPI的巨大成功之后,tiangolo用同样的原则为我们带来了Typer[1]:一个新的库,它能让你利用

  • Python中使用第三方库xlrd来读取Excel示例

    本篇文章介绍如何使用xlrd来读取Excel表格中的内容,xlrd是第三方库,所以在使用前我们需要安装xlrd.另外我们一般会使用xlwt来写Excel,所以下一篇文章我们会来介绍如何使用xlwt来写Excel.xlrd下载:xlrd 0.8.0 安装xlrd 安装xlrd,只需运行setup即可,另外你也可以直接解压缩到你的project中,也可以直接用 xlrd的API 获取Excel,这里称之为work book 复制代码 代码如下: open_workbook(file_name) 获取

  • 详解webpack提取第三方库的正确姿势

    我们在用webpack打包是时候,常常想单独提取第三方库,把它作为稳定版本的文件,利用浏览缓存减少请求次数.常用的提取第三方库的方法有两种 CommonsChunkPlugin DLLPlugin 区别:第一种每次打包,都要把第三方库也运行打包一次,第二种方法每次打包只打包项目文件,我们只要引用第一次打包好的第三方压缩文件就行了 CommonsChunkPlugin方法简介 我们拿vue举例 const vue = require('vue') { entry: { // bundle是我们要打

随机推荐