Props 就是properties 的缩写,我们可以使用Props把任意类型的数据传递给子组件。子组件本身不能设置它的props ,只能从父组件继承。我们来看下面一个例子:
// 示例1
var MessageBox = React.createClass({
render:function(){
var msgs = [];
this.props.messages.forEach(function(msg,index){
msgs.push(
<p>码农说: {msg}</p>
)
});
return (
<div>
<h1>{this.props.title}</h1>
{msgs}
</div>
)
}
});
var title = '来自props:';
var subMessages = [
'我会代码搬砖',
'我会花式搬砖',
'不说了,工头叫我回去搬砖了。。。。。。',
];
ReactDOM.render( <MessageBox title={title} messages={subMessages}/>,
document.getElementById('example')
)
上述代码中,我们通过 props 向子组件 MessageBox
传递了两个属性:title
和 messages
,然后在子组件中通过 this.props.title
和 this.props.messages
来获取相应的数据。因为this.props.messages
为数组,因此调用 forEach
方法来遍历。最后效果如下:
这里有一个潜在问题,当父组件没有向子组件传递相应的 props 时,子组件无法通过this.props.key
来获取相应的数据。这时就需要用到 getDefaultProps()
。
1、getDefaultProps()
getDefaultProps()
方法与上一节提到的 getInitialState()
作用相似,不同的是getDefaultProps()
为 props
设置默认值,而getInitialState()
是为 state
设置默认值。
// 示例2
var MessageBox = React.createClass({
getDefaultProps:function(){
return {
title:'默认title:',
messages: ['默认的子消息'],
}
},
render:function(){
var msgs = [];
this.props.messages.forEach(function(msg,index){
msgs.push(
<p>码农说: {msg}</p>
)
});
return (
<div>
<h1>{this.props.title}</h1>
{msgs}
</div>
)
}
});
var title = '来自props:';
var subMessages = [
'我会代码搬砖',
'我会花式搬砖',
'不说了,工头叫我回去搬砖了。。。。。。',
];
ReactDOM.render( <MessageBox />,
document.getElementById('example')
)
示例2相对于示例1多了 getDefaultProps
,在getDefaultProps
设置了title
和 messages
的默认值,当父组件没有向子组件传递props
时,调用默认值,结果如下:
2、PropTypes
这里还有一个问题,当我们传入的 props
数据类型与所需的数据类型不一致时,会报错。参考示例3:
//示例3
var MessageBox = React.createClass({
getDefaultProps:function(){
return {
title:'默认title:',
messages: ['默认的子消息'],
}
},
render:function(){
var msgs = [];
this.props.messages.forEach(function(msg,index){
msgs.push(
<p>码农说: {msg}</p>
)
});
return (
<div>
<h1>{this.props.title}</h1>
{msgs}
</div>
)
}
});
var title = '来自props:';
var subMessages = [
'我会代码搬砖',
'我会花式搬砖',
'不说了,工头叫我回去搬砖了。。。。。。',
];
ReactDOM.render( <MessageBox title={title} messages={title}/>,
document.getElementById('example')
)
例如我们在传递messages
时,一不小心写成了{title}
,由于messages
是一个数组,而{title}
是字符串,字符串无法调用forEach()
方法,因此会报下错误:
Uncaught TypeError: this.props.messages.forEach is not a function(…)
这时就需要对传入的props
类型进行验证,Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
//示例4
var MessageBox = React.createClass({
propTypes:{
messages: React.PropTypes.array.isRequired,
},
getDefaultProps:function(){
return {
title:'默认title:',
messages: ['默认的子消息'],
}
},
render:function(){
var msgs = [];
this.props.messages.forEach(function(msg,index){
msgs.push(
<p>码农说: {msg}</p>
)
});
return (
<div>
<h1>{this.props.title}</h1>
{msgs}
</div>
)
}
});
var title = '来自props:';
var subMessages = [
'我会代码搬砖',
'我会花式搬砖',
'不说了,工头叫我回去搬砖了。。。。。。',
];
ReactDOM.render( <MessageBox title={title} messages={title}/>,
document.getElementById('example')
)
加上了 propTypes 验证之后,如果 props 类型不对时,控制台会打印警告信息:
Warning: Failed propType: Invalid prop `messages` of type `string` supplied to `MessageBox`, expected `array`.
React.PropTypes 提供很多验证器 (validator),更多验证器说明如下:
React.createClass({
propTypes: {
// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 可以被渲染的对象 numbers, strings, elements 或 array
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 可以是多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定 shape 参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 任意类型加上 `isRequired` 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,
// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
},
/* ... */
});
关于propTypes的更多信息,查看React 官网说明。
3、{…props}
还可以使用JSX 的展开语告把 props 设置成一个对象,这样就不需要在标签中逐个列出 props ,通过 {…props} 就可以把props对象传递到子组件,如下示例5:
// 示例5
var MessageBox = React.createClass({
render:function(){
var props = {
title: '来自props:',
messages: [
'我会代码搬砖',
'我会花式搬砖',
'不说了,工头叫我回去搬砖了。。。。。。',
]
};
return (
<Submessage {...props} />
)
}
});
var Submessage = React.createClass({
propTypes:{
messages: React.PropTypes.array.isRequired,
},
getDefaultProps:function(){
return {
title:'默认title:',
messages: ['默认的子消息'],
}
},
render:function(){
var msgs = [];
this.props.messages.forEach(function(msg,index){
msgs.push(
<p>码农说: {msg}</p>
)
});
return (
<div>
<h1>{this.props.title}</h1>
{msgs}
</div>
)
}
});
ReactDOM.render( <MessageBox />,
document.getElementById('example')
)
上述程序中,在 MessageBox
中设置了props对象。然后,在实例化 Submessage
的时候通过 {...props}
将props对象传递到子组件中,子组件获取 title 和 message 进行相应的数据展示。
4、this.props.children
上面示例中我们提到的 this.props 表示组件的属性,但是有一个例外,就是 this.props.children 属性,它表示组件的所有子节点。
// 示例6
var NotesList = React.createClass({
render: function() {
return (
<ol>
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>
);
}
});
ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.getElementById('example')
);
运行结果:
我们可以看到 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取。
this.props.children 的值有三种可能:
- 如果当前组件没有子节点,它就是 undefined ;
- 如果有一个子节点,数据类型是 object ;
- 如果有多个子节点,数据类型就是 array