React: React的属性验证机制
一、简介
在开发中,属性变量类型的验证,几乎是任何语言都必须关注的问题,因为如果传入的数据类型不对,轻者程序运行仅仅是给出警告⚠️,严重的会直接导致程序中断,APP闪退或者web页面挂掉,这是很严重的bug问题。如我们所知,JavaScript是一种弱类型的语言,这意味着开发者可以随意地修改变量值的数据类型,而且JavaScript虚拟机对此操作并不会产生异议,虽然这种机制大大地提高了编程的灵活性,但是也隐藏了一个极大的crash风险。React组件为此提供了一种声明和验证属性类型的方法,称为自动属性验证机制。这种机制将会大幅度减少调试时间,能够及时把不正确的属性类型触发警告⚠️,以便开发者准确快速的定位bug,然后进行修复。
二、验证器类型
React内置了自动属性验证器,如下所示:
数组类型 React.PropTyps.array
布尔类型 React.PropTyps.bool
函数类型 React.PropTyps.func
数字类型 React.PropTyps.number
对象类型 React.PropTyps.object
字符串类型 React.PropTyps.string
React也支持自定义属性验证器,可以使用typeof字段和“===”进行判断并抛出异常,例如:
布尔类型 (props, propName) => (typeof props[propName] === "boolean") ? null : new Error(`${propName} is not boolean`)
函数类型 (props, propName) => (typeof props[propName] === "function") ? null : new Error(`${propName} is not function`)
数字类型 (props, propName) => (typeof props[propName] === "number") ? null : new Error(`${propName} is not number`)
对象类型 (props, propName) => (typeof props[propName] === "object") ? null : new Error(`${propName} is not object`)
字符串类型 (props, propName) => (typeof props[propName] === "string") ? null : new Error(`${propName} is not string`)
字符类类型和长度限制嵌套 (props, propName) => (typeof props[propName] === 'string') ?
((props[propName].length > 5) ? new Error("长度超过5") : null) : new Error(`${propName} is not sring`)
三、验证器声明
React中对属性类型的声明使用了关键字propTypes。对于createClass组件、ES6类组件和无状态函数式组件,它们的声明方式有所区别,如下所示:
createClass组件:
//创建组件 const Component = React.createClass({ //属性验证声明 propTypes: { title: React.PropTypes.string, items: React.PropTypes.array }
......... })
ES6类组件:
//创建组件 class Component extends React.Component{ ......... } //属性验证声明 Component.propTypes = { title: React.PropTypes.string, items: React.PropTypes.array }
无状态函数式组件:
//创建组件 const Component = ({title,items}) => { ....... } //属性验证声明 Component.propTypes = { title: React.PropTypes.string, items: React.PropTypes.array }
四、验证器属性限制
React中,在没有提供属性数据的情况下渲染组件会导致JavaScript报错,从而拖垮整个Web应用。对于这种数据缺少的错误,React属性验证器提供了isRequired字段要求属性数据是必须项,如果不填或者为空,React将会在触发错误之前就在控制台发出警告信息,提醒开发者异常原因。如下:
//创建组件 const Component = React.createClass({ //属性验证声明 propTypes: { title: React.PropTypes.string.isRequired, items: React.PropTypes.array.isRequired } ......... })
五、简单示例
需求: 定一个动物组件,拥有种族类型属性type,动物数组属性kinds,在Web页面上展示type标题和kinds个数。
1、传入正确的数据,动物数组个数显示正常:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Hello React</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> const AnimalComponent = React.createClass({ render(){ const {type, kinds} = this.props const divStyle = { width:400, height:100, backgroundColor:"#DAE", color:"red", textAlign:"center" } return ( <div className="animal" style={divStyle}> <h1>{type}</h1> <p> <span>{kinds.length} kinds animals</span> </p> </div> ) } }) const kinds = ["cat","dog","pig","Cattle","sheep"] ReactDOM.render( <AnimalComponent type="Breastfeeding animation" kinds={kinds} />, document.getElementById("container") ) </script> </body> </html>
2、如果将数组kinds当做字符串传入,Web页面虽然没有挂掉,但是动物数组个数却显示异常,如果开发者检查不仔细,那就是线上的bug了:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Hello React</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> const AnimalComponent = React.createClass({ render(){ const {type, kinds} = this.props const divStyle = { width:400, height:100, backgroundColor:"#DAE", color:"red", textAlign:"center" } return ( <div className="animal" style={divStyle}> <h1>{type}</h1> <p> <span>{kinds.length} kinds animals</span> </p> </div> ) } }) const kinds = "this is a cat" ReactDOM.render( <AnimalComponent type="Breastfeeding animation" kinds={kinds} />, document.getElementById("container") ) </script> </body> </html>
3、如果此时添加属性验证器,再将数组kinds当做字符串传入,Web页面没有挂掉的同时,控制台还会爆出警告,可以及时发现数据问题:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Hello React</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> const AnimalComponent = React.createClass({ propTypes: { type: React.PropTypes.string, kinds: React.PropTypes.array }, render(){ const {type, kinds} = this.props const divStyle = { width:400, height:100, backgroundColor:"#DAE", color:"red", textAlign:"center" } return ( <div className="animal" style={divStyle}> <h1>{type}</h1> <p> <span>{kinds.length} kinds animals</span> </p> </div> ) } }) const kinds = "this is a cat" ReactDOM.render( <AnimalComponent type="Breastfeeding animation" kinds={kinds} />, document.getElementById("container") ) </script> </body> </html>
4、如果此时添加属性验证器的同时,还限制属性是isRequried,那么在渲染组件时,不传递参数,Web页面直接会挂掉成空白页了,当然可以提前设置默认参数避免这种问题:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Hello React</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> const AnimalComponent = React.createClass({ propTypes: { type: React.PropTypes.string.isRequired, kinds: React.PropTypes.array.isRequired }, render(){ const {type, kinds} = this.props const divStyle = { width:400, height:100, backgroundColor:"#DAE", color:"red", textAlign:"center" } return ( <div className="animal" style={divStyle}> <h1>{type}</h1> <p> <span>{kinds.length} kinds animals</span> </p> </div> ) } }) ReactDOM.render( <AnimalComponent/>, document.getElementById("container") ) </script> </body> </html>
5、如果此时添加自定义的属性验证器,再将数组kinds当做字符串传入,Web页面没有挂掉的同时,控制台还可以弹出自定义的警告信息:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Hello React</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> const AnimalComponent = React.createClass({ propTypes: { type: React.PropTypes.string, kinds: (props, propName) => (typeof props[propName] === 'string') ? new Error(`${propName} is not array`) : null }, render(){ const {type, kinds} = this.props const divStyle = { width:400, height:100, backgroundColor:"#DAE", color:"red", textAlign:"center" } return ( <div className="animal" style={divStyle}> <h1>{type}</h1> <p> <span>{kinds.length} kinds animals</span> </p> </div> ) } }) const kinds = "this is a cat" ReactDOM.render( <AnimalComponent type="Breastfeeding animation" kinds={kinds} />, document.getElementById("container") ) </script> </body> </html>