【react】利用prop-types第三方庫對組件的props中的變量進行類型檢測

本節主要討論的是與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中傳遞一個數字,數組和一個布爾型數值,但由於你剛一下子追完了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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章