利用prop-types第三方庫對組件的props中的變量進行類型檢測
1.引言——JavaScript就是一個熊孩子
1.1對于JSer們來說,js是自由的,但同時又有許多讓人煩惱的地方。javascript很多時候就是這么一個熊孩子,他很多時候并不會像C和java這些“好孩子”那樣循規(guī)蹈矩。因此給我們帶來許多煩惱
<1>運行時候控制臺報錯:uncaught error,這尤其令人惱火的是系統(tǒng)告訴我們有錯誤但是又不告訴我們錯誤發(fā)生在哪里。試想一下,你到一個地方旅游迷了路,一個當?shù)氐男芎⒆右恢毙ξ馗谀愫箢^告訴你:“你走錯啦!”。但是不告訴你應該怎么走,你會不會很想揍他一頓?(╬ ̄皿 ̄)
<2>運行時報了確定的錯誤,然而我們發(fā)現(xiàn)這TM完全是一條驢唇不對馬嘴的錯誤報告。甚至于去stackoverflow上尋找答案,卻發(fā)現(xiàn)提問的錯誤場景跟自己的根本是兩碼事。讓我們回到1中場景,假如這個熊孩子很好心地告訴了你路線,結(jié)果你走到天黑發(fā)現(xiàn)被熊孩子狠狠得耍了,導致你不得不在大晚上露宿街頭,你會不會比1中場景更想揍他一頓?(╬ ̄皿 ̄)
<3>你主觀地寫錯了了一個變量的類型,比如把字符串1寫成數(shù)字1,但是系統(tǒng)“很好心”地不報錯誤提示。(我們都不需要特別的進行類型聲明當然不會報告錯誤提示啦)而這卻可能就是你接下來bug的源頭。讓我們回到1,2中場景,假如這個熊孩子知道你這個外地人絕逼是走錯路了,但當你問路:“我走對路了嗎?”時候,他笑靨如花滿面春風得點點頭,讓你充滿信心充滿希望得一條路走到黑。我想你此時的心情不會比1和2中的要好(╬ ̄皿 ̄)
<2>中情況有時候比較難以避免
<1>中情況我們可以通過熟悉主要的6種uncaught error的情形加以判斷。(在下一篇文章里我會討論這個問題)
<3>中的情況呢,完全可以用類型檢測的方式加以避免,這也就是我這篇文章所講到的內(nèi)容
本節(jié)主要討論的是與react配套的類型檢測庫——prop-types的運用
今天我在這篇文章里面介紹的內(nèi)容,就是通過react的propTypes進行類型檢測,。顧名思義prop-types就是對react組件中props對象中的變量進行類型檢測的,因為props是react數(shù)據(jù)流的管道,我們通過prop-types就可以輕松監(jiān)控react里大多數(shù)據(jù)的變量類型先介紹下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檢測全部數(shù)據(jù)類型的變量
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中傳遞一個數(shù)字,數(shù)組和一個布爾型數(shù)值,但由于你過度疲憊,把它們都寫成了字符串,雖然渲染是正常的,但這可能會導致你接下來調(diào)用一些方法的時候發(fā)生錯誤,而系統(tǒng)并不提供任何提示。


讓我們給它加上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屬性名稱,錯誤的變量類型,屬性所在的組件名稱,預期的正確的變量類型,錯誤代碼的位置以及其他更詳細的信息。
這種“人為控制”的報錯比一般的系統(tǒng)報錯看起來應該要親切自然得多吧...你大可以說:這個error是我“私人定制”的呦 (//▽//)

propTypes 能用來檢測全部數(shù)據(jù)類型的變量,包括基本類型的的string,boolean,number,以及引用類型的object,array,function,甚至還有ES6新增的symbol類型
Son.propTypes = {
optionalArray: PropTypes.array,//檢測數(shù)組類型
optionalBool: PropTypes.bool,//檢測布爾類型
optionalFunc: PropTypes.func,//檢測函數(shù)(Function類型)
optionalNumber: PropTypes.number,//檢測數(shù)字
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}
/>)
}
}
結(jié)果是輸出臺不報任何錯誤,(當然你改成undefined也是同樣效果)。

3.2 通過oneOfType實現(xiàn)多選擇檢測——可規(guī)定多個檢測通過的數(shù)據(jù)類型
上個例子中類型檢測的要求是一個變量對應一個數(shù)據(jù)類型,也就是規(guī)定的變量類型只有一個。那么怎樣能讓它變得靈活一些,比如規(guī)定多個可選的數(shù)據(jù)類型都為檢測通過呢?PropTypes里的oneOfType方法可以做到這一點,oneOfType方法接收參數(shù)的是一個數(shù)組,數(shù)組元素是你希望檢測通過的數(shù)據(jù)類型。
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(){
//分別渲染數(shù)字的11和字符串的11
return (<div>
<Son number = {'字符串11'}/>
<Son number = {11}/>
</div>)
}
}
這時候,因為在類型檢測中,number屬性的規(guī)定類型包括字符串和數(shù)字兩種,所以此時控制臺無報錯

當然,如果你改為number = {數(shù)組或其他類型的變量},那么這時就會報錯了

3.3 通過oneOf實現(xiàn)多選擇檢測——可規(guī)定多個檢測通過的變量的值
3.2是規(guī)定了多個可檢測通過的數(shù)據(jù)類型,那么同樣的道理,我們也可以規(guī)定多個可檢測通過的變量的值,這就要用到PropTypes里的oneOf方法,和PropTypes方法一樣oneOf方法接收參數(shù)的是一個數(shù)組,數(shù)組元素是你希望檢測通過的變量的值,比如我們把上面類型檢測的部分改成:
Son.propTypes = {
number:PropTypes.oneOf(
[12,13]
)
}
那么運行時就會報這樣一段錯誤:

3.4 arrayOf,objectOf實現(xiàn)多重嵌套檢測
試想一下,如果我們檢測的是基本類型的變量,那么這自然是很簡單的,但當我們要檢測的是一個引用類型的變量呢?當我們除了檢測這個變量是否符合規(guī)定的引用類型外(Object/array),還想要進一步檢測object中的屬性變量或array中數(shù)組元素的數(shù)據(jù)類型時,單靠上面的方法已經(jīng)不能滿足要求了。這時候就要用到PropTypes的arrayOf,objectOf方法。
arrayOf接收一個參數(shù),這個參數(shù)是規(guī)定的數(shù)組元素的數(shù)據(jù)類型。objectOf接收的參數(shù)則是屬性的數(shù)據(jù)類型
我們對上述例子做些修改:
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']}/>,報錯

【注意】雖然報錯但是這并不會影響程序的正常運行(譬如上面我們看到渲染仍然是正常的),因為本質(zhì)上說類型檢測報的是非致命性錯誤warning而不是致命性錯誤error(區(qū)別在于是否影響了正常運行)。對objectOf也是同樣的做法
3.5 通過shape方法檢測目標對象不同屬性的不同數(shù)據(jù)類型
如果你認真思考一下的話,你會發(fā)現(xiàn)3.4中的objectOf有一個缺陷,就是它內(nèi)部的屬性的數(shù)據(jù)類型被強行規(guī)定為一種,但通常一個對象里應該是有多種不同類型的屬性了,那么這時候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是數(shù)字類型,但如果你不想控制number的類型而僅僅是想控制它的必要性呢?難道寫成number:isRequired或number:PropTypes.isRequired? 這個時候PropTypes.any就登場啦!它代表了該變量可取任何一種數(shù)據(jù)類型,所以你可以寫成這樣——number: PropTypes.any.isRequired
3.7 應對更復雜的類型檢測——將PropTypes的屬性值寫成函數(shù)
Son.propTypes = {
prop:function(props,propName,componentName){
if(/*判斷條件*/){
return new Error(/*錯誤的參數(shù)*/)
}
}
}
在屬性prop的類型檢測中,屬性值是一個函數(shù),在這里props是包含prop的props對象,propName是prop的屬性名,componentName是props所在的組件名稱,函數(shù)的返回值是一個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的靜態(tài)類屬性的支持下,你可以這樣寫:
class Son extends React.Component{
static propTypes = {
//..類型檢測
}
render(){
return (/* 渲染*/)
}
}
但注意,這在ES7下生效
5.props-types的獨立與react.PropTypes的棄用
在上面我是利用props-types這個獨立的第三方庫來進行類型檢測的,但在不久前(react V15.5以前),它使用的是react內(nèi)置的類型檢測,而不是第三方庫(也就是說我們現(xiàn)在的prop-types是當初以react內(nèi)置的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
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關文章
JavaScript 類型轉(zhuǎn)換的詳細實現(xiàn)
本文主要介紹了JavaScript 類型轉(zhuǎn)換的詳細實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-02-02
JavaScript自定義Webpack配置實現(xiàn)流程介紹
本系列主要整理前端面試中需要掌握的知識點。本節(jié)介紹webpack如何優(yōu)化前端性能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-10-10
利用 Chrome Dev Tools 進行頁面性能分析的步驟說明(前端性能優(yōu)化)
這篇文章主要介紹了利用 Chrome Dev Tools 進行頁面性能分析的步驟說明(前端性能優(yōu)化),本文給大家介紹的非常想詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02
bootstrap可編輯下拉框jquery.editable-select
這篇文章主要介紹了bootstrap可編輯下拉框jquery.editable-select的相關資料,需要的朋友可以參考下2017-10-10
關于事件mouseover ,mouseout ,mouseenter,mouseleave的區(qū)別
mouseover ,mouseout ,mouseenter,mouseleave,都是鼠標點擊而觸發(fā)的事件,各自代表什么意思,有哪些區(qū)別呢?下面跟著腳本之家小編一起看看吧2015-10-10

