1. 程式人生 > >react prop-types的使用講解

react prop-types的使用講解

1.引言--JavaScript就是一個熊孩子

1.1對於JSer們來說,JS是自由的,但同時又有許多讓人煩惱的地方.javascript 很多時候就是這麼一個熊孩子,他很多時候並不會像Ç和java的這些“好孩子”那樣循規蹈矩。因此給我們帶來許多煩惱

<1>執行時候控制檯報錯:未記錯誤,尤其這令人惱火的的英文系統-告訴我們有錯誤但是又不告訴我們錯誤發生在哪裡試想一下,你到一個地方旅遊迷了路,一個當地的熊孩子一直笑嘻嘻地跟在你後頭告訴你?!“你走錯啦”但是不告訴你應該怎麼走,你會不會很想揍他一頓(╬皿)

<2>執行時報了確定的錯誤,然而我們發現這TM完全是一條驢脣不對馬嘴的錯誤報告。甚至於去計算器上尋找答案,卻發現提問的錯誤場景跟自己的根本是兩碼事

。讓我們回到1中場景,假如這個熊孩子很好心地告訴了你路線,結果你走到天黑髮現被熊孩子狠狠得耍了,導致你不得不在大晚上露宿街頭,你會不會比1中場景更想揍他一頓?(╬皿¯)

<3>你主觀地寫錯了了一個變數的型別,比如把字串1寫成數字1,但是系統“很好心”地不報錯誤提示。(我們都不需要特別的進行型別聲明當然不會報告錯誤提示啦)而這卻可能就是你接下來錯誤的源頭讓我們回到1,2中場景。假如這個熊孩子知道你這個外地人絕逼是走錯路了,但當你問路:“我走對路了嗎?”時候,他笑靨如花滿面春風得點點頭,讓你充滿信心充滿希望得一條路走到黑。我想你此時的心情不會比1和2中的要好(╬皿¯)

<2>

中情況有時候比較難以避免

<1>中情況我們可以通過熟悉主要的6種uncaught error的情形加以判斷。(在下一篇文章裡我會討論這個問題)

<3>中的情況呢,完全可以用型別檢測的方式加以避免,這也就是我這篇文章所講到的內容

本節主要討論的是與反應配套的型別檢測庫--prop型別的運用

今天我在這篇文章裡面介紹的內容,就是通過反應過來的propTypes進行型別檢測。顧名思義丙型別就是對反應元件中道具物件中的變數進行型別檢測的,因為道具的英文反應資料流的管道,我們通過丙型別就可以輕鬆監控反應裡大多資料的變數型別先介紹下propTypes的基本用法。

2.prop型別基礎入門

2.1首先你需要通過在終端npm install prop-types安裝一個叫prop-types的第三方包

2.2然後通過下面的寫法對你的某一個元件的道具中的變數進行型別檢測:

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

比如這個例子,我們通過道具從父元件向子元件傳遞屬性,你原本試圖通過數目,陣列和布林這三個屬性分別向子中傳遞一個數字,陣列和一個布林型數值,但由於你剛一下子追完了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'}
                        />)
                  }
}

然後我們就能看到報的錯誤了,而且這個時候,報的錯誤包括錯誤的道具屬性名稱,錯誤的變數型別,屬性所在的元件名稱,預期的正確的變數型別,錯誤程式碼的位置以及其他更詳細的資訊。

這種“人為控制”的報錯比一般的系統報錯看起來應該要親切自然得多吧...你大可以說:這個錯誤是我“私人定製”的呦(//▽//)

propTypes能用來檢測全部資料型別的變數,包括基本型別的的字串,布林值,數字,以及引用型別的物件,陣列,函式,甚至還有ES6新增的符號型別

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型別
}

【注意】下面這些是從官方英文文件裡引用過來的,你大概能夠注意到,五種基本型別中的不確定和空並不在此列,propTypes型別檢測的缺憾之一是,對於不確定的和無效的值,它無法捕捉錯誤

讓我們把上述例項中的父元件傳遞給子元件修改一下,改成:

class Father extends React.Component{
    render(){
       return (<Son
                 number = {null}
                 array = {null}
                 boolean = {null}
                />)
             }
}

結果是輸出臺不報任何錯誤,(當然你改成未定義也是同樣效果)。

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 = {陣列或其他型別的變數},那麼這時就會報錯了

3.3  通過oneOf實現多選擇檢測-可規定多個檢測通過的變數的值

3.2是規定了多個可檢測通過的資料型別,那麼同樣的道理,我們也可以規定多個可檢測通過的變數的值,這就要用到PropTypes裡的oneOf方法,和PropTypes方法一樣oneOf方法接收引數的是一個數組,陣列元素是你希望檢測通過的變數的值,比如我們把上面型別檢測的部分改成:

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

那麼執行時就會報這樣一段錯誤:

3.4 arrayOf,objectOf實現多重巢狀檢測

試想一下,如果我們檢測的是基本型別的變數,那麼這自然是很簡單的,但當我們要檢測的是一個引用型別的變數呢?當我們除了檢測這個變數是否符合規定的引用型別外(物件/陣列),還想要進一步檢測物件中的屬性變數或陣列中陣列元素的資料型別時,單靠上面的方法已經不能滿足要求了。這時候就要用到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']} /> ,報錯

【注意】雖然報錯但是這並不會影響程式的正常執行(譬如上面我們看到渲染仍然是正常的),因為本質上說型別檢測報的是非致命性錯誤的警告而不是致命性錯誤的錯誤(區別在於是否影響了正常執行)。對objectOf也是同樣的做法

3.5  通過形狀方法檢測目標物件不同屬性的不同資料型別

如果你認真思考一下的話,你會發現3.4中的objectOf有一個缺陷,就是它內部的屬性的資料型別被強行規定為一種,但通常一個物件裡應該是有多種不同型別的屬性了,那麼這時候objectOf就不符合要求了,我們應該使用形狀方法,其用法:

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:'彭湖灣',年齡:20}} />改成<Son object = {{name:'彭湖灣',年齡:'20'}} /> ,然後就能喜聞樂見得報錯了

3.6通過isRequired檢測道具中某個必要的屬性(如果該屬性不存在就報錯)

有時候,我們在對某個變數進行型別檢測時,我們不僅要求它符合預期的型別,同時也要求它是必須寫入的,這時候就要用到isRequired。

【分析】

Son.propTypes = {
          number:PropTypes.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
}

再執行,我們就又可以喜聞樂見得看到錯誤了:

【注意】在這裡給大家提個問題:我們上述的寫法是數量:PropTypes.number.isRequired,這要求數是數字型別,但如果你不想控制數的型別而僅僅是想控制它的必要性呢?難道寫成號: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_-])[email protected]([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://www.cnblogs.com/penghuwan/p/6796139.html