1.引言——JavaScript就是一個(gè)熊孩子
創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)整合營(yíng)銷推廣、網(wǎng)站重做改版、平定網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5建站、商城系統(tǒng)網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為平定等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
1.1對(duì)于JSer們來(lái)說(shuō),js是自由的,但同時(shí)又有許多讓人煩惱的地方。javascript很多時(shí)候就是這么一個(gè)熊孩子,他很多時(shí)候并不會(huì)像C和java這些“好孩子”那樣循規(guī)蹈矩。因此給我們帶來(lái)許多煩惱
<1>運(yùn)行時(shí)候控制臺(tái)報(bào)錯(cuò):uncaught error,這尤其令人惱火的是系統(tǒng)告訴我們有錯(cuò)誤但是又不告訴我們錯(cuò)誤發(fā)生在哪里。試想一下,你到一個(gè)地方旅游迷了路,一個(gè)當(dāng)?shù)氐男芎⒆右恢毙ξ馗谀愫箢^告訴你:“你走錯(cuò)啦!”。但是不告訴你應(yīng)該怎么走,你會(huì)不會(huì)很想揍他一頓?(╬ ̄皿 ̄)
<2>運(yùn)行時(shí)報(bào)了確定的錯(cuò)誤,然而我們發(fā)現(xiàn)這TM完全是一條驢唇不對(duì)馬嘴的錯(cuò)誤報(bào)告。甚至于去stackoverflow上尋找答案,卻發(fā)現(xiàn)提問(wèn)的錯(cuò)誤場(chǎng)景跟自己的根本是兩碼事。讓我們回到1中場(chǎng)景,假如這個(gè)熊孩子很好心地告訴了你路線,結(jié)果你走到天黑發(fā)現(xiàn)被熊孩子狠狠得耍了,導(dǎo)致你不得不在大晚上露宿街頭,你會(huì)不會(huì)比1中場(chǎng)景更想揍他一頓?(╬ ̄皿 ̄)
<3>你主觀地寫錯(cuò)了了一個(gè)變量的類型,比如把字符串1寫成數(shù)字1,但是系統(tǒng)“很好心”地不報(bào)錯(cuò)誤提示。(我們都不需要特別的進(jìn)行類型聲明當(dāng)然不會(huì)報(bào)告錯(cuò)誤提示啦)而這卻可能就是你接下來(lái)bug的源頭。讓我們回到1,2中場(chǎng)景,假如這個(gè)熊孩子知道你這個(gè)外地人絕逼是走錯(cuò)路了,但當(dāng)你問(wèn)路:“我走對(duì)路了嗎?”時(shí)候,他笑靨如花滿面春風(fēng)得點(diǎn)點(diǎn)頭,讓你充滿信心充滿希望得一條路走到黑。我想你此時(shí)的心情不會(huì)比1和2中的要好(╬ ̄皿 ̄)
<2>中情況有時(shí)候比較難以避免
<1>中情況我們可以通過(guò)熟悉主要的6種uncaught error的情形加以判斷。(在下一篇文章里我會(huì)討論這個(gè)問(wèn)題)
<3>中的情況呢,完全可以用類型檢測(cè)的方式加以避免,這也就是我這篇文章所講到的內(nèi)容
本節(jié)主要討論的是與react配套的類型檢測(cè)庫(kù)——prop-types的運(yùn)用
今天我在這篇文章里面介紹的內(nèi)容,就是通過(guò)react的propTypes進(jìn)行類型檢測(cè),。顧名思義prop-types就是對(duì)react組件中props對(duì)象中的變量進(jìn)行類型檢測(cè)的,因?yàn)閜rops是react數(shù)據(jù)流的管道,我們通過(guò)prop-types就可以輕松監(jiān)控react里大多數(shù)據(jù)的變量類型先介紹下propTypes的基本用法。
2.prop-types基礎(chǔ)入門
2.1首先你需要通過(guò)在終端npm install prop-types安裝一個(gè)叫prop-types的第三方包
2.2然后通過(guò)下面的寫法對(duì)你的某一個(gè)組件的props中的變量進(jìn)行類型檢測(cè):
yourComponent.propTypes = { 屬性1:屬性1的變量類型, 屬性2:屬性2的變量類型 //... }
3.propTypes的使用全解
3.1利用propTypes檢測(cè)全部數(shù)據(jù)類型的變量
import React from 'react' class Son extends React.Component{ render(){ return ({this.props.number}) } } class Father extends React.Component{ render(){ return (
{this.props.array}
{this.props.boolean.toString()}) } }
比如這個(gè)例子,我們通過(guò)props從父組件向子組件傳遞屬性,你原本試圖通過(guò)number,array和boolean這三個(gè)屬性分別向Son中傳遞一個(gè)數(shù)字,數(shù)組和一個(gè)布爾型數(shù)值,但由于你過(guò)度疲憊,把它們都寫成了字符串,雖然渲染是正常的,但這可能會(huì)導(dǎo)致你接下來(lái)調(diào)用一些方法的時(shí)候發(fā)生錯(cuò)誤,而系統(tǒng)并不提供任何提示。
讓我們給它加上propTypes的類型檢測(cè):
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({this.props.number}) } } Son.propTypes = { number:PropTypes.number, array:PropTypes.array, boolean:PropTypes.bool } class Father extends React.Component{ render(){ return (
{this.props.array}
{this.props.boolean.toString()}) } }
然后我們就能看到報(bào)的錯(cuò)誤了,而且這個(gè)時(shí)候,報(bào)的錯(cuò)誤包括錯(cuò)誤的props屬性名稱,錯(cuò)誤的變量類型,屬性所在的組件名稱,預(yù)期的正確的變量類型,錯(cuò)誤代碼的位置以及其他更詳細(xì)的信息。
這種“人為控制”的報(bào)錯(cuò)比一般的系統(tǒng)報(bào)錯(cuò)看起來(lái)應(yīng)該要親切自然得多吧...你大可以說(shuō):這個(gè)error是我“私人定制”的呦 (//▽//)
propTypes 能用來(lái)檢測(cè)全部數(shù)據(jù)類型的變量,包括基本類型的的string,boolean,number,以及引用類型的object,array,function,甚至還有ES6新增的symbol類型
Son.propTypes = { optionalArray: PropTypes.array,//檢測(cè)數(shù)組類型 optionalBool: PropTypes.bool,//檢測(cè)布爾類型 optionalFunc: PropTypes.func,//檢測(cè)函數(shù)(Function類型) optionalNumber: PropTypes.number,//檢測(cè)數(shù)字 optionalObject: PropTypes.object,//檢測(cè)對(duì)象 optionalString: PropTypes.string,//檢測(cè)字符串 optionalSymbol: PropTypes.symbol,//ES6新增的symbol類型 }
【注意】下面這些是從官方英文文檔里引用過(guò)來(lái)的,你大概能夠注意到,五種基本類型中的undefined和null并不在此列,propTypes類型檢測(cè)的缺憾之一是,對(duì)于undefined和null的值,它無(wú)法捕捉錯(cuò)誤
讓我們把上述實(shí)例中的Father組件傳遞給Son組件修改一下,改成:
class Father extends React.Component{ render(){ return () } }
結(jié)果是輸出臺(tái)不報(bào)任何錯(cuò)誤,(當(dāng)然你改成undefined也是同樣效果)。
3.2 通過(guò)oneOfType實(shí)現(xiàn)多選擇檢測(cè)——可規(guī)定多個(gè)檢測(cè)通過(guò)的數(shù)據(jù)類型
上個(gè)例子中類型檢測(cè)的要求是一個(gè)變量對(duì)應(yīng)一個(gè)數(shù)據(jù)類型,也就是規(guī)定的變量類型只有一個(gè)。那么怎樣能讓它變得靈活一些,比如規(guī)定多個(gè)可選的數(shù)據(jù)類型都為檢測(cè)通過(guò)呢?PropTypes里的oneOfType方法可以做到這一點(diǎn),oneOfType方法接收參數(shù)的是一個(gè)數(shù)組,數(shù)組元素是你希望檢測(cè)通過(guò)的數(shù)據(jù)類型。
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({this.props.number}) } } Son.propTypes = { number:PropTypes.oneOfType( [PropTypes.string,PropTypes.number] ) } class Father extends React.Component{ render(){ //分別渲染數(shù)字的11和字符串的11 return () } }
這時(shí)候,因?yàn)樵陬愋蜋z測(cè)中,number屬性的規(guī)定類型包括字符串和數(shù)字兩種,所以此時(shí)控制臺(tái)無(wú)報(bào)錯(cuò)
當(dāng)然,如果你改為number = {數(shù)組或其他類型的變量},那么這時(shí)就會(huì)報(bào)錯(cuò)了
3.3 通過(guò)oneOf實(shí)現(xiàn)多選擇檢測(cè)——可規(guī)定多個(gè)檢測(cè)通過(guò)的變量的值
3.2是規(guī)定了多個(gè)可檢測(cè)通過(guò)的數(shù)據(jù)類型,那么同樣的道理,我們也可以規(guī)定多個(gè)可檢測(cè)通過(guò)的變量的值,這就要用到PropTypes里的oneOf方法,和PropTypes方法一樣oneOf方法接收參數(shù)的是一個(gè)數(shù)組,數(shù)組元素是你希望檢測(cè)通過(guò)的變量的值,比如我們把上面類型檢測(cè)的部分改成:
Son.propTypes = { number:PropTypes.oneOf( [12,13] ) }
那么運(yùn)行時(shí)就會(huì)報(bào)這樣一段錯(cuò)誤:
3.4 arrayOf,objectOf實(shí)現(xiàn)多重嵌套檢測(cè)
試想一下,如果我們檢測(cè)的是基本類型的變量,那么這自然是很簡(jiǎn)單的,但當(dāng)我們要檢測(cè)的是一個(gè)引用類型的變量呢?當(dāng)我們除了檢測(cè)這個(gè)變量是否符合規(guī)定的引用類型外(Object/array),還想要進(jìn)一步檢測(cè)object中的屬性變量或array中數(shù)組元素的數(shù)據(jù)類型時(shí),單靠上面的方法已經(jīng)不能滿足要求了。這時(shí)候就要用到PropTypes的arrayOf,objectOf方法。
arrayOf接收一個(gè)參數(shù),這個(gè)參數(shù)是規(guī)定的數(shù)組元素的數(shù)據(jù)類型。objectOf接收的參數(shù)則是屬性的數(shù)據(jù)類型
我們對(duì)上述例子做些修改:
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({this.props.array}) } } Son.propTypes = { array:PropTypes.arrayOf(PropTypes.number) } class Father extends React.Component{ render(){ return () } }
正常渲染,然后我們把
【注意】雖然報(bào)錯(cuò)但是這并不會(huì)影響程序的正常運(yùn)行(譬如上面我們看到渲染仍然是正常的),因?yàn)楸举|(zhì)上說(shuō)類型檢測(cè)報(bào)的是非致命性錯(cuò)誤warning而不是致命性錯(cuò)誤error(區(qū)別在于是否影響了正常運(yùn)行)。對(duì)objectOf也是同樣的做法
3.5 通過(guò)shape方法檢測(cè)目標(biāo)對(duì)象不同屬性的不同數(shù)據(jù)類型
如果你認(rèn)真思考一下的話,你會(huì)發(fā)現(xiàn)3.4中的objectOf有一個(gè)缺陷,就是它內(nèi)部的屬性的數(shù)據(jù)類型被強(qiáng)行規(guī)定為一種,但通常一個(gè)對(duì)象里應(yīng)該是有多種不同類型的屬性了,那么這時(shí)候objectOf就不符合要求了,我們應(yīng)該使用shape方法,其用法:
PropTypes.shape({ 屬性1:類型1, 屬性2:類型2, //... }),
舉個(gè)例子:
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({'我的名字叫' + this.props.object.name}) } } Son.propTypes = { object:PropTypes.shape({ name:PropTypes.string, age:PropTypes.number }) } class Father extends React.Component{ render(){ return (
{'我的年齡是' + this.props.object.age}) } }
無(wú)報(bào)錯(cuò),把
3.6 通過(guò)isRequired檢測(cè)props中某個(gè)必要的屬性(如果該屬性不存在就報(bào)錯(cuò))
有時(shí)候,我們?cè)趯?duì)某個(gè)變量進(jìn)行類型檢測(cè)時(shí),我們不僅要求它符合預(yù)期的類型,同時(shí)也要求它是必須寫入的,這時(shí)候就要用到isRequired。
【分析】
Son.propTypes = { number:PropTypes.number }
這段代碼的作用是當(dāng)你在props中寫入number屬性且number屬性類型錯(cuò)誤時(shí)給予報(bào)錯(cuò)提示,可如果你壓根就沒(méi)有寫入number屬性呢?沒(méi)錯(cuò),什么錯(cuò)誤都不會(huì)報(bào)。這就是使用isRequired的必要性
【栗子】
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({this.props.number}) } } Son.propTypes = { number:PropTypes.number } class Father extends React.Component{ render(){ return () } }
控制臺(tái)無(wú)任何輸出
如果我們改成:
Son.propTypes = { number:PropTypes.number.isRequired }
再運(yùn)行,我們就又可以喜聞樂(lè)見(jiàn)得看到錯(cuò)誤了:
【注意】在這里給大家提個(gè)問(wèn)題:我們上述的寫法是number:PropTypes.number.isRequired,這要求number是數(shù)字類型,但如果你不想控制number的類型而僅僅是想控制它的必要性呢?難道寫成number:isRequired或number:PropTypes.isRequired?這個(gè)時(shí)候PropTypes.any就登場(chǎng)啦!它代表了該變量可取任何一種數(shù)據(jù)類型,所以你可以寫成這樣——number: PropTypes.any.isRequired
3.7 應(yīng)對(duì)更復(fù)雜的類型檢測(cè)——將PropTypes的屬性值寫成函數(shù)
Son.propTypes = { prop:function(props,propName,componentName){ if(/*判斷條件*/){ return new Error(/*錯(cuò)誤的參數(shù)*/) } } }
在屬性prop的類型檢測(cè)中,屬性值是一個(gè)函數(shù),在這里props是包含prop的props對(duì)象,propName是prop的屬性名,componentName是props所在的組件名稱,函數(shù)的返回值是一個(gè)Error對(duì)象
import React from 'react' import PropTypes from 'prop-types'; class Son extends React.Component{ render(){ return ({this.props.email}) } } 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 () } }
在這里我們利用正則表達(dá)式檢測(cè)傳遞到Son組件的email屬性是否符合郵箱格式,如果不符合就拋出錯(cuò)誤,那么2314838004顯然不符合這一要求,所以我們就得到下面的demo:(其實(shí)加上qq.com就是我的郵箱啦 哈哈)
4.ES7下類型檢測(cè)的新寫法:
可能你覺(jué)得把propTypes寫在類外看起來(lái)有些怪怪的,在ES7的靜態(tài)類屬性的支持下,你可以這樣寫:
class Son extends React.Component{ static propTypes = { //..類型檢測(cè) } render(){ return (/* 渲染*/) } }
但注意,這在ES7下生效
5.props-types的獨(dú)立與react.PropTypes的棄用
在上面我是利用props-types這個(gè)獨(dú)立的第三方庫(kù)來(lái)進(jìn)行類型檢測(cè)的,但在不久前(react V15.5以前),它使用的是react內(nèi)置的類型檢測(cè),而不是第三方庫(kù)(也就是說(shuō)我們現(xiàn)在的prop-types是當(dāng)初以react內(nèi)置的PropTypes對(duì)象為基礎(chǔ)分離出來(lái)的)
翻譯成中文就是:
所以說(shuō)在你也可以這樣進(jìn)行類型檢測(cè),雖然并不推薦(為了保持向下兼容這在最新版本的react上仍然是可用的)
Son.propTypes = { number:React.PropTypes.number }
6.參考資料:
react官方文檔/高級(jí)指導(dǎo)/類型檢測(cè)(docs/advanced guide/Typechecking with propTypes)
https://facebook.github.io/react/docs/typechecking-with-proptypes.html
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持創(chuàng)新互聯(lián)!