1、React里有一个非常常用的模型就是对组件做一层抽象。组件对外公开一个简单的属性(Props)来实现功能,但内部细节坑内有分厂复杂的实现。可以使用JSX展开属性来合并现有的props和其他值:
return <Commponent{...this.props}more="balues" />;
如果不使用JSX,可以使用一些队形复制方法如ES6的object。assign或UnderScore_.extend。
returnComponent(Object.assign({},this.props,{more:'values’}));
PS:JSX展开属性:
如果事先知道组件需要的全部PRops(属性),JSX很容易地这样写:
var component =<Componentfoo={x} bar ={y} />;
修改Props是不好的:
如果知道要设置那些Props那么现在最好不要设置它:
var component = <Component/>
coponent.props.foo=x;
component.pros.bar=y;
这样是反模式,因为React 不能帮你检查属性类型(propTypes)。这样即使你的 属性类型有错误也不能得到清晰的错误提示。
Props应该被当作禁止修改的。修改 props 对象可能会导致预料之外的结果,所以最好不要去修改 props 对象。
展开属性:
现在你可以使用 JSX的新特性 - 展开属性:
var props= {};
props.foo = x;
props.bar = y;
var component= <Component {...props}/>;
传入对象的属性会被复制到组件内。
它能被多次使用,也可以和其它属性一起用。注意顺序很重要,后面的会覆盖掉前面的。
var props= { foo:'default' };
var component= <Component {...props} foo={'override'}/>;
console.log(component.props.foo); // 'override'
奇怪的标记...:
这个 ... 操作符(也被叫做)已经被 ES6 数组 支持。相关的还有 ES7规范草案中的Object 剩余和展开属性(Rest and SpreadProperties)。我们利用了这些还在制定中标准中已经被支持的特性来使 JSX 拥有更优雅的语法。
2、手动传递
大部分情况下你应该显式地向下传递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!
</FancyCheckbox>,
document.body
);
但是name这些属性怎么办?还有title、onMouseOve这些props?
在JSX里使用 ... 传递
有时把所有的属性都传递下去是不安全和啰嗦的,这时可以使用解析赋值中的剩余属性特征来把未知属性批量提取出来。
列出所有要当前使用的属性,后面要跟着...other。
var {checked,...other}= this.props;
这样能确保所有props传下去,除了这些已经被使用了的。
var FancyCheckbox =React.createClass({
render: function() {
var { checked, ...other } = this.props;
var fancyClass = checked ? 'FancyChecked' :'FancyUnchecked';
// `other`包含 { onClick: console.log }但 checked属性除外
return (
<div {...other} className={fancyClass}/>
);
}
});
React.render(
<FancyCheckbox checked={true}onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.body
);
在传递这些未知的 other 属性时,要经常使用解构赋值模式。
var FancyCheckbox =React.createClass({
render: function() {
var fancyClass = this.props.checked ?'FancyChecked' : 'FancyUnchecked';
//反模式:`checked`会被传到里面的组件里
return (
<div {...this.props}className={fancyClass} />
);
}
});
3、使用和传递同一个Prop
如果组件需要使用一个属性又要往下传递,可以直接使用 checked={checked} 再传一次。这样做比传整个 this.props 对象要好,因为更利于重构和语法检查。
var FancyCheckbox =React.createClass({
render: function() {
var { checked, title, ...other } =this.props;
var fancyClass = checked ? 'FancyChecked' :'FancyUnchecked';
var fancyTitle = checked ? 'X ' + title :'O ' + title;
return (
<label>
<input {...other}
checked={checked}
className={fancyClass}
type="checkbox"
/>
{fancyTitle}
</label>
);
}
});
PS:顺序很重要,把 {...other} 放到 JSX props 前面会使它不被覆盖。上面例子中我们可以保证input 的 type 是 "checkbox"。
4、剩余属性和展开属性
剩余属性可以把对象剩下的属性提取到一个新的对象。会把所有在解构赋值中列出的属性剔除。
var{ x, y, ...z }={ x:1, y:2, a:3, b:4};
x;// 1
y;// 2
z;// { a: 3, b: 4 }
PS:这是 ES7 草案 中的试验特性,使用 JSX 命令行工具 配合 --harmony 标记来启用 ES7 语法。
5、使用Underscore传递
如果不使用JSX,可以使用一些库来实现相同效果。
Underscore提供 _.omit 来过滤属性,_.extend 复制属性到新的对象。
javascript
var FancyCheckbox = React.createClass({
render: function() {
var checked = this.props.checked;
var other = _.omit(this.props, 'checked'
);
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
return (
React.DOM.div(_.extend({}, other, { className: fancyClass })
)
); }
});