最直接的定义: React为了明确表示类型错误所在位置而提供的一项类型检查功能。
propTypes(包括之后会提到的defaultProps)在我们开发过程中并不是必要的,但是对于我们成为一个更好的开发者(也可以帮我们在项目中快速定位到错误所在),学习它就很有必要了。
在这里感谢@会煮咖啡的猫,他写的那篇文章——React类型检查很详细的介绍了这点。
首先我们先来了解一下日常开发中常见的一些错误类型吧。
在rollbar上面有一篇博客,介绍了在上千个文章中重复出现的错误的种类,包括
- Uncaught TypeError: cannnot read property '*' of null
- TypeError: 'undefined' is not an object
- TypeError: 'null' is not an object
- Script Error
- TypeError : object doesn't support property
- TypeError: 'undefined' is not a function
- Uncaught RangeError
- TypeError : can not read property 'length'
- Uncaught Error: Cannot set property
- Reference Error: event is not defined
在这里我们找几个我们日常开发比较常见的说明一下。
- Uncaught TypeErrpr: cannot read property of null
常见于查询定义未赋值的变量上的属性值。
下文中,我们在初次渲染的时候试图遍历state里面items的每一项。
class Quiz extends Component {
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
聪明的你一定看出来问题所在了——state未初始化,所以items默认是一个undefined,对其进行遍历自然会报错了——此外,在ComponentWillMount里面请求也是不可取的,因为此时组件尚未加载完成,在这里虽然请求到了数据 但是setState不会触发重渲染,也就得不出我们想要的页面的效果了。
- TypeError: 'undefined' || 'null' is not an object
经过一番不严谨的测试,似乎只有在safari内核的浏览器中才会有这两个错误,edge && chrome(新版)一般直接就报 cannnot read property 这些。
(不得不说外国人真的习惯用这个浏览器了,不仅如此,国内谷歌同样冠绝群雄(但是谷歌的占内存是真的恐怖,感觉比大型游戏都能吃:在这里推荐一下edge浏览器——不得不说,微软终于醒了,做了点好东西——这个浏览器个人感觉可以直接从chrome迁移过来,体验类似但是内存松了一口气))
- script error
这个一般多发于js尝试使用跨域等功能而发生了部分未知的错误导致的。例如你试图在CDN上面托管你的JS代码,任何报错都会只返回一个script error:出现这个现象的原因是浏览器的安全保护机制防止跨域传输数据。
- TypeError: Object doesn't support property
本错误一般见于IE的骨灰级浏览器,现在推崇的Edge已经不会有这个报错了(取而代之的是Uncaught TypeError: this.***() is not a function)
- uncaught RangeError
最常见的就是超内存了。
类似这种,无限重复调用,就会触发。
此外当函数的参数值超出预期范围时也会报错。
之后的都是比较容易理解的,这里不再赘叙。
propTypes
为了快速标示以上错误中类型错误所在处,我们推荐在react中使用propTypes中给传入的props设定值类型。
import propTypes from 'prop-types';
随便创建一个类:
export default class Random extends React.PureComponent{
constructor(props){
super(props);
this.state = {};
}
render(){
return (
<div>{this.props.name}, how old are you?</div>
)
}
}
我们可以在类内外指定propTypes:
Random.propTypes = {
name: PropTypes.string,
}
// 或者在类里面定义
export default class Random extends React.PureComponent{
static propTypes = {
name: PropTypes.string
}
}
如果传的值不是string类型 则会报错
PropTypes类型:
static propTypes = {
supposedArray: PropTypes.array, // 数组
supposedBoolean: PropTypes.bool, // 布尔值
supposedFunction: PropTypes.func, //函数
supposedNumber: PropTypes.number, // 数值
supposedObject: PropTypes.object, // 对象
supposedString: PropTypes.string, // 字符串
supposedSymbol: PropTypes.symbol, // symbol值
// 放松了部分限制,numbers,string, elements,或者包含这些类型的数组(对象等仍旧会返回错误)
supposedNode: PropTypes.node,
// react元素
supposedElement: PropTypes.element,
// 使用JS的instanceof运算符,设定prop是类的一个实例
supposedClass: PropTypes.instanceOf(aClass),
// 声明prop是特定的值||特定的范围中的一个
supposedValue: PropTypes.oneOf(['a','b']),
// 声明prop是多个类型中的一种
supposedType: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(aClass)
])
// 一个由某种类型的值构成的数组
supposedNumberArray: PropTypes.arrayOf(PropTypes.number),
// 一个属性值是某种类型的对象
supposedSetValueObject: PropTypes.objectOf(PropTypes.string),
// 一个设定了部分属性的对象(只要这个对象的存在该属性且值类型符合即可)
supposedSetTypeObject: PropTypes.shapeOf({
name: PropTypes.string,
})
// 一个设定了所有属性的对象(若存在其他属性会返回一个warning)
supposedExactObject: PropTypes.exact({
name: PropTypes.string,
})
//任何数据类型的值
supposedAny: PropTypes.any.isRequired, // 如果不传值会返回一个warning(如果不想这样 可以去掉required)
// 此外 之前上述的所有值都可以在后面增加isRequired
}
此外,还有自定义的验证器。例如: (以下文档出自React官方文档)
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
Extra:
children: PropTypes.element.isRequired可以限制元素仅有一个子元素。
defaultProps
设置默认props(有点像是设置默认值的感觉)
static defaultProps = {
name: 'myName'
}
defaultProps用于确保this.props.name在父组件没有指定其值时,有一个默认值。propTypes类型检查发生在defaultProps赋值后,所以类型检查也适用于defaultProps。
以上。
参考文档: