世界上最伟大的投资就是投资自己的教育
react 组件间的通信方法
1. 介绍
react 推荐的开发方法,是高度组件化,就是一个大应用,切分成不同的组件,再把它们组合在一起。
这样就会能以避免到不同的组件之间的交流,比如传递数据,而这样又有好多种情况,可以从父组件或从子组件传递是最简单的,有些时候你会发现,把数据从一个组件传递到另一个组件是一件好复杂的事,这可能是另外的情况。
我把组件的数据传递分为四种情况来一一讲述。
2. 父子间
这种方式是最简单,也是最常见的。
父组件要把数据传递给子组件,就通过props
传过去。子组件可以通过this.props
方法来获得传递过来的数据,这种是最基本,很常见的,几乎每个写 react 的人都会用到吧。
然而 react 的数据流向是单向的,如果子组件要传递数据给父组件就要一些技巧,不过这种情况也很常见。
就是首先父组件传递一个方法名给子组件,这个方法必须先在父组件定义好,比如叫父组件叫ElementGroup
,子组件叫Element
,这时候可以在渲染子组件的时候,传递一个方法,叫deleteElement
。
<Element handleDeleteElement={ this.deleteElement } />
deleteElement
方法已经在父组件定义好了。
deleteElement(element) {
const index = this.state.elements.indexOf(element)
const elements = ReactAddonsUpdate(this.state.elements, { $splice: [[index, 1]] })
this.replaceState({elements: elements})
}
这个时候,在子组件Element
就可以通过this.props.handleDeleteElement
方法来调动,并且可以把数据传给父组件。
比如
this.props.handleDeleteElement(this.props.meta_element)
这样就可以轻易把this.props.meta_element
传递给父组件的deleteElement
方法的element
参数。
下面摘自reactjs-two-components-communicating的一段代码:
var Filters = React.createClass({
handleFilterChange: function() {
var value = this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(value);
},
render: function() {
return <input type="text" ref="filterInput" onChange={this.handleFilterChange} placeholder="Filter" />;
}
});
var List = React.createClass({
getInitialState: function() {
return {
listItems: ['Chicago', 'New York', 'Tokyo', 'London', 'San Francisco', 'Amsterdam', 'Hong Kong'],
nameFilter: ''
};
},
handleFilterUpdate: function(filterValue) {
this.setState({
nameFilter: filterValue
});
},
render: function() {
var displayedItems = this.state.listItems.filter(function(item) {
var match = item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
return (match !== -1);
}.bind(this));
var content;
if (displayedItems.length > 0) {
var items = displayedItems.map(function(item) {
return <li>{item}</li>;
});
content = <ul>{items}</ul>
} else {
content = <p>No items matching this filter</p>;
}
return (
<div>
<Filters updateFilter={this.handleFilterUpdate} />
<h4>Results</h4>
{content}
</div>
);
}
});
React.renderComponent(<List />, document.body);
可以在这里具体体会上述的思想。
3. 兄弟间
兄弟间的组件,我们有一个共同的特点,就是父级组件,所以它们的数据传递主要是靠父级组件作为中间桥梁。
下面用具体的代码体会:
var Filters = React.createClass({
handleFilterChange: function() {
var value = this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(value);
},
render: function() {
return <input type="text" ref="filterInput" onChange={this.handleFilterChange} placeholder="Filter" />;
}
});
var List = React.createClass({
render: function() {
var content;
if (this.props.items.length > 0) {
var items = this.props.items.map(function(item) {
return <li>{item}</li>;
});
content = <ul>{items}</ul>
} else {
content = <p>No items matching this filter</p>;
}
return (
<div className="results">
<h4>Results</h4>
{content}
</div>
);
}
});
var ListContainer = React.createClass({
getInitialState: function() {
return {
listItems: ['Chicago', 'New York', 'Tokyo', 'London', 'San Francisco', 'Amsterdam', 'Hong Kong'],
nameFilter: ''
};
},
handleFilterUpdate: function(filterValue) {
this.setState({
nameFilter: filterValue
});
},
render: function() {
var displayedItems = this.state.listItems.filter(function(item) {
var match = item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
return (match !== -1);
}.bind(this));
return (
<div>
<Filters updateFilter={this.handleFilterUpdate} />
<List items={displayedItems} />
</div>
);
}
});
React.renderComponent(<ListContainer />, document.body);
4. 嵌套太深的继承关系
嵌套太深,比如就算是同级的,有好多层嵌套,这个时候如果还用上面的方法,那就是噩梦了,写起来和管理起来都会令人头疼。
下面来说说解决此问题的几种方法。
5. context(上下文)
context这个可以让任意组件进行数据交换,这也是 react 提供的方法,不过不建议用,我觉得也不需要去懂,只知道这个可以用。
6. 事件模式
这种模式有点类似于 backbone 的 listen_to,也有点类似于订阅消费模式,如果用这种模式,可以让任意的组件互传数据的,但是缺点可能就是会写些侵入式代码。
比如你可以让任何组件都能使用类似消息通知这样的功能,可以先在最顶级组件上使用订阅功能。
EventEmitter.subscribe('alert', function(info){
this.showAlert(info)
}.bind(this))
在任何需要使用这个功能的组件上就可以这样:
EventEmitter.dispatch('alert', '操作成功')
你可以使用类似EventEmitter这种库来实现这样的功能。
也可以自己实现一个简单版本的:
export default {
_events: {},
dispatch: function (event, data) {
if (!this._events[event]) return // no one is listening to this event
for (let i = 0; i < this._events[event].length; i++)
this._events[event][i](data)
},
subscribe: function (event, callback) {
if (!this._events[event]) this._events[event] = [] // new event
this._events[event].push(callback)
},
unSubscribe: function(event){
if(this._events && this._events[event]) {
delete this._events[event]
}
}
}
有兴趣的可以看下这个库: https://github.com/facebook/emitter
7. redux
如果你使用过 redux,或了解过它的理念,你肯定知道为什么 redux,能解决这个组件交流的问题。
// 想要绑定什么就传过来reducer中的state, 比如state.header
const mapStateToProps = (state, ownProps) => ({
response: state.header
})
const mapDispatchToProps = (dispatch, ownProps) => ({
actions: bindActionCreators(HeaderActions, dispatch)
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(Header)
8. 总结
我是这样觉得的,如果你使用了 redux,那就不用在乎组件的数据交流了,它本身可以解决,如果没有使用的话,可以考虑下事件模式。
本站文章均为原创内容,如需转载请注明出处,谢谢。
© 汕尾市求知科技有限公司 | Rails365 Gitlab | 知乎 | b 站 | csdn
粤公网安备 44152102000088号 | 粤ICP备19038915号
Top
特别喜欢这类总结性的文档👍