【react】利用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{javascript

  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中傳遞一個數字,數組和一個布爾型數值,但因爲你剛一會兒追完了50多集《人民的名義》,致使你過分疲憊,把它們都寫成了字符串,雖然渲染是正常的,但這可能會致使你接下來調用一些方法的時候發生錯誤,而系統並不提供任何提示。
 

 
讓咱們給它加上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)
 
 
相關文章
相關標籤/搜索