共计 4336 个字符,预计需要花费 11 分钟才能阅读完成。
一、组件协同使用
目的:
- 逻辑清晰
- 代码模块化
- 封装细节
- 代码的复用
方法:嵌套和mixin
1.组件嵌套
父组件通过this.props把属性传递给子组件,子组件通过this.refs委托方法和属性给父组件。
举个栗子
import React from 'react';
import { render } from 'react-dom';
const ProfilePic = (props) => {
return (
<img src={'http://graph.facebook.com/' + props.username + '/picture'} />
);
}
const ProfileLink = (props) => {
return (
<a href={'http://www.facebook.com/' + props.username}>
{props.username}
</a>
);
}
const Avatar = (props) => {
return (
<div>
<ProfilePic username={props.username} />
<ProfileLink username={props.username} />
</div>
);
}
render(
<Avatar username="pwh" />,
document.getElementById('example')
);
2.Mixins
简单的讲mixin就是抽离可以共用的行为,在需要时透过 mixins 属性设定给组件,提高代码的复用率。
举个官方的栗子:
var IntervalMixin = {
setInterval:function(callback,intercal){
var token = setInterval(callback,intercal);
this.__intervals.push(token);
return token;
},
componentDidMount:function(){
this.__intervals = []
},
componentWillUnmount = function(){
this.__intervals.map(clearInterval);
}
};
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
}
};
var TickTock = React.createClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
React.render(
<TickTock />,
document.getElementById('example')
);
React自带的Mixins(react-with-addons.js)
React.addons = { TransitionGroup: ReactTransitionGroup, CSSTransitionGroup: ReactCSSTransitionGroup, //用于处理动画和过渡,这些通常实现起来都不简单,例如在一个组件移除之前执行一段动画。 LinkedStateMixin: LinkedStateMixin,//用于简化用户表单输入数据和组件 state 之间的双向数据绑定。 classSet:classSet//用于更加干净简洁地操作 DOM 中的
class
字符串。 PureRenderMixin: ReactComponentWithPureRenderMixin,//在某些场景下的性能检测器。 batchedUpdates: function () { if ("development" !== 'production') { "development" !== 'production' ? warning(warnedAboutBatchedUpdates, 'React.addons.batchedUpdates is deprecated. Use ' + 'ReactDOM.unstable_batchedUpdates instead.') : undefined; warnedAboutBatchedUpdates = true; } return ReactUpdates.batchedUpdates.apply(this, arguments); }, cloneWithProps: cloneWithProps,//用于实现 React 组件浅复制,同时改变它们的 props 。 createFragment: ReactFragment.create, shallowCompare: shallowCompare, update: update//一个辅助方法,使得在 JavaScript 中处理不可变数据更加容易。 };
二、组件循环插入子元素的方法
如果组件中包含通过循环插入的子元素,为了保证重新渲染 UI 的时候能够正确显示这些子元素,每个元素都需要通过一个特殊的 key
属性指定一个唯一值。
//1.
const ListItemWrapper = (props) => <li>{props.data.text}</li>;
//2.
const MyComponent = (props) => {
var items = {};
this.props.results.forEach((result) => {
items['result-' + result.id] = <li>{result.text}</li>;
});
return (
<ol>
{items}
</ol>
);
}
//3.
render: function() {
var results = this.props.results;
return (<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>);
}
//4.
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>
);
}
});
this.props.children
组件标签里面包含的子元素会通过 props.children
传递进来。
一般来说,可以直接将这个属性作为父组件的子元素 render:
const Parent = (props) => <div>{props.children}</div>;
props.children
通常是一个组件对象的数组,但是当只有一个子元素的时候,props.children
将是这个唯一的子元素,而不是数组了。
React.Children
提供了额外的方法方便操作这个属性。
- React.Children.map:array React.Children.map(object children, function fn [, object thisArg])
- React.Children.forEach:React.Children.forEach(object children, function fn [, object thisArg])
- React.Children.count:number React.Children.count(object children)
- React.Children.only:object React.Children.only(object children)
- React.Children.toArray:array React.Children.toArray(object children)
三、侵入式插件
查看实例:
var SuperSelect = React.createClass({
render:function(){
return;
},
//挂载插件
componentDidMount:function(){
var el = this.el = document.createElement('div');
this.getDOMNode().appendChild(el);
$(el).superSelect(this.props);
$(el).on('superSelect',this.handleSuperSelectChange);
},
handleSuperSelectChange:function(){
//dosomething
},
//卸载插件
componentWillUnmount:function(){
this.getDOMNode().removeChild(this.el);
$(this.el).off();
}
})
下面有两种重新装卸插件的方式:
1.简单可靠
componentDidUpdate:function(){
this.componentWillUnmount();
this.componentDidMount();
}
2.高效,清晰
componentWillReceiveProps:function(){
$(this.el).superSelect("update",nextProps);
}
正文完