React 复合组件
2016-03-16 17:37
447 查看
来源
一、动机:关注分离
通过复用那些接口定义良好的组件来开发新的模块化组件,我们得到了与使用函数和类相似的好处。具体来说就是能够通过开发简单的组件把程序的不同关注面分离。如果为程序开发一套自定义的组件库,那么就能以最适合业务场景的方式来展示你的用户界面。
二、从属关系
上面例子中,
把从属关系与父子关系加以区别至关重要。从属关系是
三、子级
实例化
四、子级校正(Reconciliation)
校正就是每次
直观来看,只是删除了
五、子组件状态管理
对于大多数组件,这没什么大碍。但是,对于使用
多数情况下,可以通过 隐藏组件而不是删除 它们来绕过这些问题。
六、动态子级
如果子组件位置会改变(如在搜索结果中)或者有新组件添加到列表开头(如在流中)情况会变得更加复杂。如果子级要在多个渲染阶段保持自己的特征和状态,在这种情况下,你可以通过给子级设置惟一标识的
当
也可以传递
7、数据流
8、性能提醒
你或许会担心如果一个拥有者有大量子级时,对于数据变化做出响应非常耗费性能。值得庆幸的是执行
但是,有时候需要做细粒度的性能控制。这种情况下,可以重写
注意:
如果在数据变化时让
一、动机:关注分离
通过复用那些接口定义良好的组件来开发新的模块化组件,我们得到了与使用函数和类相似的好处。具体来说就是能够通过开发简单的组件把程序的不同关注面分离。如果为程序开发一套自定义的组件库,那么就能以最适合业务场景的方式来展示你的用户界面。
<div id="example"></div> <script type="text/jsx"> //组合实例 var Avatar = React.createClass({ render: function () { return ( <div> <AvatarPic username = {this.props.username} /> <AvatarLink username = {this.props.username} /> </div> ); } }); var ProfilePic = React.createClass({ render: function () { return ( <div className="avatar-pic"> <img width="100" height="100" alt="头像" src={'http://graph.facebook.com/'+ this.props.username + '/picture'} /> </div> ) } }); var ProfileLink = React.createClass({ render: function () { return ( <div className="avatar-link"> <a href={'http://graph.facebook.com/'+ this.props.username}> {this.props.username} </a> </div> ) } }); React.render( <Avatar username = "qqli" />, //pwh document.getElementById('example') ) /** * 注意事项: * ProfilePic组件: 首字母需要大写 * {this.props.username}:调用属性值,需要使用{}包裹,作为属性值中有字符串的情况href={'http://graph.facebook.com/'+ this.props.username} */ </script>
二、从属关系
上面例子中,
Avatar拥有
ProfilePic和
ProfileLink的实例。拥有者 就是给其它组件设置
props的那个组件。更正式地说, 如果组件
Y在
render()方法是创建了组件
X,那么
Y就拥有
X。上面讲过,组件不能修改自身的
props- 它们总是与它们拥有者设置的保持一致。这是保持用户界面一致性的关键性原则。
把从属关系与父子关系加以区别至关重要。从属关系是
React特有的,而父子关系简单来讲就是
DOM里的标签的关系。在上一个例子中,
Avatar拥有
div、
ProfilePic和
ProfileLink实例,
div是
ProfilePic和
ProfileLink实例的父级(但不是拥有者)。
三、子级
实例化
React组件时,你可以在开始标签和结束标签之间引用在
React组件或者
Javascript表达式:
<Parent><Child /></Parent>
Parent能通过专门的
this.props.children props读取子级。
this.props.children是一个不透明的数据结构: 通过
React.Children工具类 来操作。
四、子级校正(Reconciliation)
校正就是每次
render方法调用后
React更新
DOM的过程。 一般情况下,子级会根据它们被渲染的顺序来做校正。例如,下面代码描述了两次渲染的过程:
// 第一次渲染 <Card> <p>Paragraph 1</p> <p>Paragraph 2</p> </Card> // 第二次渲染 <Card> <p>Paragraph 2</p> </Card>
直观来看,只是删除了
<p>Paragraph 1</p>。事实上,
React先更新第一个子级的内容,然后删除最后一个组件。
React是根据子级的顺序来校正的。
五、子组件状态管理
对于大多数组件,这没什么大碍。但是,对于使用
this.state来自多次渲染过程中里维持数据的状态化组件,这样做潜在很多问题。
多数情况下,可以通过 隐藏组件而不是删除 它们来绕过这些问题。
// 第一次渲染 <Card> <p>Paragraph 1</p> <p>Paragraph 2</p> </Card> // 第二次渲染 <Card> <p style={{display: 'none'}}>Paragraph 1</p> <p>Paragraph 2</p> </Card>
六、动态子级
如果子组件位置会改变(如在搜索结果中)或者有新组件添加到列表开头(如在流中)情况会变得更加复杂。如果子级要在多个渲染阶段保持自己的特征和状态,在这种情况下,你可以通过给子级设置惟一标识的
key来区分。
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 上:
// 错误! 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> ); } }); // 正确 :) var ListItemWrapper = React.createClass({ render: function() { return <li>{this.props.data.text}</li>; } }); var MyComponent = React.createClass({ render: function() { return ( <ul> {this.props.results.map(function(result) { return <ListItemWrapper key={result.id} data={result}/>; })} </ul> ); } });
也可以传递
object来做有
key的子级。
object的
key会被当作每个组件的
key。但是一定要牢记
JavaScript并不总是保证属性的顺序会被保留。实际情况下浏览器一般会保留属性的顺序,除了 使用 32位无符号数字做为
key的属性。数字型属性会按大小排序并且排在其它属性前面。一旦发生这种情况,
React渲染组件的顺序就会混乱。可以在
key前面加一个字符串前缀来避免:
render: function() { var items = {}; this.props.results.forEach(function(result) { // 如果 result.id 看起来是一个数字(比如短哈希),那么 // 对象字面量的顺序就得不到保证。这种情况下,需要添加前缀 // 来确保 key 是字符串。 items['result-' + result.id] = <li>{result.text}</li>; }); return ( <ol> {items} </ol> ); }
7、数据流
React里,数据通过上面介绍过的
props从拥有者流向归属者。这就是高效的单向数据绑定
(one-way data binding):拥有者通过它的
props或
state计算出一些值,并把这些值绑定到它们拥有的组件的
props上。因为这个过程会递归地调用,所以数据变化会自动在所有被使用的地方自动反映出来。
8、性能提醒
你或许会担心如果一个拥有者有大量子级时,对于数据变化做出响应非常耗费性能。值得庆幸的是执行
JavaScript非常的快,而且
render()方法一般比较简单,所以在大部分应用里这样做速度极快。此外,性能的瓶颈大多是因为
DOM更新,而非
JS执行,而且
React会通过批量更新和变化检测来优化性能。
但是,有时候需要做细粒度的性能控制。这种情况下,可以重写
shouldComponentUpdate() 方法返回
false来让
React跳过对子树的处理。参考 React reference docs 了解更多。
注意:
如果在数据变化时让
shouldComponentUpdate() 返回
false,
React就不能保证用户界面同步。当使用它的时候一定确保你清楚到底做了什么,并且只在遇到明显性能问题的时候才使用它。不要低估
JavaScript的速度,
DOM操作通常才是慢的原因。
相关文章推荐
- React 生命周期
- iOS开发之旅--React native使用IDE推荐webstorm
- MVVM Tutorial with ReactiveCocoa
- 抛开react,如何理解virtual dom和immutability
- React中state和props的区别
- react-native 学习之TextInput组件篇
- react native 开发环境配置
- React组件详细介绍及其生命周期函数
- react-native 学习之Image篇
- react、redux什么的都用起来 【1】我不是双向绑定
- ReactNative的组件架构设计
- React系列——React主要内容简介
- 把react什么的都用起来 【0】预备——开始
- react-native 在任意view fragment activity中集成react
- React-native 调用原生组件
- react-native 调用原生模块详解
- 解决ReactNative崩溃:Can't find variable: __fbBatchedBridge
- 我在集成ReactNative过程中踩过的那些坑
- windows安装React Native开发运行环境
- windows安装React Native开发运行环境