@ttingtu
2015-12-28T05:30:33.000000Z
字数 3040
阅读 1894
react
这篇文章主要写React最赞的一个特性:组合性
通过复用那些拥有完美接口定义的组件,可以构建模块化的组件,这样做的带来的好处与使用函数或者类相同。特别的,简单的构建新组件能够使应用app的关注点分离。通过在应用中构建一个定制的组件库,能够使你的UI更好的匹配对应的域。
以下例子创建了一个简单的Avatar组件,该组件通过调用Facebook图片API展示了用户的头像及用户名。
var Avatar = React.createClass({
render: function() {
return (
<div>
<ProfilePic username={this.props.username} />
<ProfileLink username={this.props.username} />
</div>
);
}
});
var ProfilePic = React.createClass({
render: function() {
return (
<img src={'https://graph.facebook.com/' + this.props.username + '/picture'} />
);
}
});
var ProfileLink = React.createClass({
render: function() {
return (
<a href={'https://www.facebook.com/' + this.props.username}>
{this.props.username}
</a>
);
}
});
ReactDOM.render(
<Avatar username="pwh" />,
document.getElementById('example')
);
在上面的例子中,Avatar实例拥有ProfilePic和ProfileLink的实例。在React中,所有者是指能够set props给其他组件的组件。正式来讲,如果一个组件X是在组件Y的render()方法中被创建,那么组件Y拥有组件X。一个组件不能修改其props值 --组件的props值与其所有者set给它的值是一致的,这条不变性准则保证了UI也是一致的。
拥有关系与父子关系是不同的。拥有关系特指存在于React中,而父子关系存在于DOM中。在上面的例子中,Avatar拥有< div >标签,ProfilePic及ProfileLink实例;而< div > 标签是ProfilePic及ProfileLink实例的父节点。
当创建一个React组件的实例时,可以在打开及关闭标签中包含其他的React组件或者javascript表达式,如下所示:
<Parent><Child /></Parent>
父节点可以通过this.props.children属性来获取其子节点。 this.props.childer是一个复杂的数据结构,可以通过React.Childer utilities来操作它们。
React多次渲染DOM是会采用整合操作。一般来说,子组件会根据渲染的顺序进行整合。比如说,假设两次渲染生成如下两个标记:
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p>Paragraph 2</p>
</Card>
直观来看, < p >Paragraph 1< /p >被移除了,实际上,React进行了以下整合操作:直接修改DOM中第一个节点的值,然后销毁第二个节点。 React是基于子节点的顺序进行整合操作。
整合操作对于大多数组件不会造成影响。但是,对于有状态的组件来说,由于还需要在render中维护this.state值,如果直接在子节点有状态的情况下进行销毁,会存在一些问题。
为了解决这一问题,在大多数情况下,可以直接隐藏元素而不是直接销毁元素:
/ Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p style={{display: 'none'}}>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
如果children一直在变化(如搜索结果)或者新组件被附到list的最前面,这种情况会变得很复杂。在这种情况下,每一个孩子 的id及state必须在render中维护,可以通过给每个孩子赋一个key来区分其id:
render: function() {
var results = this.props.results;
return (
<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>
);
}
当React整合这些带有key属性的孩子时,它能确保每个孩子能够被重排或者销毁。
key必须直接在数组中的组件中被赋值,而不是在数组中的每个组件的HTML容器中。
// WRONG!
var ListItemWrapper = React.createClass({
render: function() {
return <li key={this.props.data.id}>{this.props.data.text}</li>;
}
});
var MyComponent = React.createClass({
render: function() {
return (
<ul>
{this.props.results.map(function(result) {
return <ListItemWrapper data={result}/>;
})}
</ul>
);
}
});
也可以直接通过传递一个ReactFragment 对象来设置其key。
在React中,从拥有组件到被拥有组件间数据传递是通过props进行的。这是一个有效的单向的数据绑定: 拥有者组件基于其props和state计算结果,并将某些结果绑定给其拥有的组件。这个操作是递归的,如果数据有修改,每一个使用它们的地方都会知晓。
可能会想,如果在一个所有者下有许多子节点,更新数据可能会耗费很大。好消息是Javascript是很快的并且render()方法也非常简单,所以在大多数应用中这是非常快的。另外 ,性能瓶颈大多数情况下是位于DOM更新而不是js执行上。React通过使用批处理和变化检测会为你进行优化。
但是,有时你想要细粒度的控制性能。如果你想要React处理时跳过子树可以通过简单的重写shouldComponentUpdate()方法并返回false。查看http://facebook.github.io/react/docs/component-specs.html可以获取更多信息。
注意:当数据已经发生更新时如果shouldComponentUpdate()返回false, React并不能保证你的UI是同步的。因此使用该 方法需谨慎,仅当你确实有一个明显的性能问题时再使用使用该方法。不要低估JavaScript相比于DOM的快速性。
原文链接:http://facebook.github.io/react/docs/multiple-components.html