一、props用法
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
1、PropTypes
组件类的PropTypes
属性,就是用来验证组件实例的属性是否符合要求。
<script type="text/jsx">
var MyTitle = React.createClass({
getDefaultProps: function () {
return {
title: "duang duang duang!"
}
},
propTypes: {
title: React.PropTypes.string.isRequired
},
changeProp: function(){
this.setProps({title: 'qqli test'});
},
render: function () {
return (
<div>
{this.props.title}
<button type="button" onClick={this.changeProp}>改变title prop</button>
</div>
)
}
});
//var data = {};
//var data = 123; //Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.
var data = 'string';
//React.render(<MyTitle title={data} />, document.getElementById("demo"));
React.render(<MyTitle />, document.getElementById("demo"));
</script>
上面的Mytitle
组件有一个title
属性。PropTypes
告诉 React
,这个 title
属性是必须的,而且它的值必须是字符串。
现在,我们设置 title
属性的值是一个数值。这样一来,title
属性就通不过验证了。控制台会显示一行错误信息。
2、默认 Prop 值 getDefaultProps
该方法可以用来设置组件属性的默认值。
var ComponentWithDefaultProps = React.createClass({
getDefaultProps: function() {
return {
value: 'default value'
};
}
/* ... */
});
当父级没有传入 props
时,getDefaultProps()
可以保证 this.props.value
有默认值,注意 getDefaultProps
的结果会被 缓存。得益于此,你可以直接使用 props
,而不必手动编写一些重复或无意义的代码。
3、单个子级
React.PropTypes.element
可以限定只能有一个子级传入。
var MyComponent = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired
},
render: function() {
return (
<div>
{this.props.children} // 有且仅有一个元素,否则会抛异常。
</div>
);
}
});
4、setProps
setProps(object nextProps[, function callback])
在同一个节点上再次调用 React.render()
来更新根组件是首选的方式,也可以调用 setProps()
来改变组件的属性,触发一次重新渲染。另外,可以传递一个可选的回调函数,该函数将会在 setProps
完成并且组件重新渲染完成之后调用。
该方法仅在根组件上面调用。也就是说,仅在直接传给 React.render()
的组件上可用,在它的子级组件上不可用。如果你倾向于在子组件上使用 setProps()
,不要利用响应式更新,而是当子组件在 render()
中创建的时候传入新的 prop
到子组件中。
5、replaceProps
replaceProps(object nextProps[, function callback])
类似于 setProps()
,但是会删除所有已存在的 props
,而不是合并新旧两个 props
对象。
6、props传递
A、手动传递
大部分情况下你应该显式地向下传递 props。这样可以确保只公开你认为是安全的内部 API 的子集。
var FancyCheckbox = React.createClass({
render: function () {
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
return (
<div className={fancyClass} onClick={this.props.onClick}>
{this.props.children}
</div>
)
}
});
React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world 999
</FancyCheckbox>,
document.getElementById("demo2")
);
但 name 这个属性怎么办?还有 title、onMouseOver 这些 props?
B、在 JSX 里使用 … 传递
有时把所有属性都传下去是不安全或啰嗦的。这时可以使用 解构赋值 中的剩余属性特性来把未知属性批量提取出来。列出所有要当前使用的属性,后面跟着 …other。
var { checked, ...other } = this.props;
这样能确保把所有 props 传下去,除了 那些已经被使用了的。
var FancyCheckbox2 = React.createClass({
render: function () {
var { checked, ...other } = this.props;
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
// `other` 包含 { onClick: console.log } 但 checked 属性除外
return (
<div {...other} className={fancyClass} />
)
}
});
React.render(
<FancyCheckbox2 checked={true} onClick={console.log.bind(console)}>
Hello world 99999
</FancyCheckbox2>,
document.getElementById("demo3")
);
上面例子中,checked 属性也是一个有效的 DOM 属性。如果你没有使用解构赋值,那么可能无意中把它传下去。
7、可检测的类型
React.createClass({
propTypes: {
// 可以声明 prop 为指定的 JS 基本类型。默认
// 情况下,这些 prop 都是可传可不传的。
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 所有可以被渲染的对象:数字,
// 字符串,DOM 元素或包含这些类型的数组。
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),
// 特定形状参数的对象
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!');
}
}
},
/* ... */
});
二、在样式props中快速制定像素值
当为内联样式指定一个像素值得时候, React 会在你的数字后面自动加上 “px” , 所以下面这样的写法是有效的:
var divStyle = {height: 10}; // rendered as "height:10px"
React.render(<div style={divStyle}>Hello World</div>, mountNode);
有时候需要保持CSS属性的独立性。下面是不会自动加 “px” 后缀的 css 属性列表:
columnCount,fillOpacity,flex,flexGrow,flexShrink,fontWeight,lineClamp,lineHeight,opacity,order,orphans,strokeOpacity,widows,zIndex,zoom
三、行内样式
在 React 中,行内样式并不是以字符串的形式出现,而是通过一个特定的样式对象来指定。在这个对象中,key
值是用驼峰形式表示的样式名,而其对应的值则是样式值,通常来说这个值是个字符串(了解更多):
var divStyle = {
color: '#f00',
backgroundImage: 'url(' + imgUrl + ')',
WebkitTransition: 'all', // 注意这里的首字母'W'是大写
msTransition: 'all' // 'ms'是唯一一个首字母需要小写的浏览器前缀
};
return (
<div style={divStyle}>{this.props.title}</div>
)
样式的 key
用驼峰形式表示,是为了方便与JS
中通过DOM
节点获取样式属性的方式保持一致(比如 'node.style.backgroundImage'
)。另外浏览器前缀除了ms
以外 首字母应该大写。想必 WebkitTransition
的首字母是“W
”就不难理解了。