blog
blog copied to clipboard
React组件通信
组件通信
在这里只讲 React 组件与组件本身的通信,组件通信主要分为三个部分:
- 父组件向子组件通信:父组件向子组件传参或者是父组件调用子组件的方法
- 子组件向父组件通信:子组件向父组件传参或者是子组件调用父组件的方法
- 兄弟组件通信:兄弟组件之间相互传参或调用 建议不要有太深的的嵌套关系
父传子
-
父组件向子组件传参 父组件向子组件参可以在子组件上绑定自定义属性,或者将父组件内部 state 的值进行绑定为子组件的属性值进行传递。
-
父组件调用子组件的方法 在子组件上绑定 ref 属性,并在子组件内部定义方法(可接受参数),在父组件内部使用
this.refs.自定义属性值.函数方法名
,进行调用,可传递参数。 -
components/parentToChild/Parent.js
// 父组件
import React from 'react';
import Child from './child';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
handleChange(e) {
this.value = e.target.value;
// 调用子组件的方法
this.refs.c1.changeChild(this.value);
}
handleClick() {
this.setState({
value: this.value
});
}
render() {
return (
<div>
我是parent
<input onChange={this.handleChange.bind(this)} />
<button className="button" onClick={this.handleClick.bind(this)}>
通知
</button>
<div>
<Child ref="c1" value={this.state.value} />
</div>
</div>
);
}
}
export default Parent;
- components/parentToChild/child.js
// 子组件
import React from 'react';
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
}
changeChild(text) {
this.setState({
text: text
});
}
render() {
return (
<div>
<p>我是Child,接受来自父组件的传参:{this.props.value}</p>
<br />
<p>我是child,来自父组件对组件内部函数的的调用:{this.state.text}</p>
</div>
);
}
}
export default Child;
- App.js
import React from 'react';
import './App.css';
import ParentToChild from './components/parentToChild/Parent';
class App extends React.Component {
render() {
return (
<div className="App">
{/* 父传子 */}
{/* <ParentToChild /> */}
</div>
);
}
}
export default App;
子传父
子组件向父组件传值,在被调用的子组件上先定义回调函数,再来单独的子组件上定义新的函数,通过 props 获取 callback 函数进行值传递.
这里的 state 可以分别定义在父组件或组子组件上
- components/sonToFather/Father.js
// Father
import React from 'react';
import Son from './son';
class Father extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
setValue(param) {
this.setState({
value: param
});
}
render() {
return (
<div>
<Son setValue={this.setValue.bind(this)}></Son>
<p>我是Father,接受子组件的传参:{this.state.value}</p>
</div>
);
}
}
export default Father;
- components/sonToFather/son.js
// son
import React from 'react';
class Son extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
}
handleChange(e) {
this.props.setValue(e.target.value);
}
render() {
return (
<div>
我是Son
<input onChange={this.handleChange.bind(this)} />
<br />
</div>
);
}
}
export default Son;
- App.js
import React from 'react';
import './App.css';
import SonToFather from './components/sonToFather/Father';
class App extends React.Component {
render() {
return (
<div className="App">
{/* 子传父 */}
<SonToFather />
</div>
);
}
}
export default App;
兄弟组件
利用共同的父组件
先将两个子组件child1
和child2
的参数传递给父组件,再由分发参数,通过refs
寻找函数方法的方式进行函数调用传参。
// Parent
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
setValue2(param) {
this.refs.c1.changeState(param);
this.setState({
value: param
});
}
setValue1(param) {
this.refs.c2.changeState(param);
this.setState({
value: param
});
}
render() {
return (
<div>
<p>我是Parent,接受子组件的传参:{this.state.value}</p>
<Child1 ref="c1" setValue={this.setValue1.bind(this)}></Child1>
<Child2 ref="c2" setValue={this.setValue2.bind(this)}></Child2>
</div>
);
}
}
// Child1
class Child1 extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
}
handleChange(e) {
this.props.setValue(e.target.value);
}
changeState(text) {
this.setState({ text: text });
}
render() {
return (
<div>
我是child1
<input onChange={this.handleChange.bind(this)} />
<p>来自子组件2的调用: {this.state.text}</p>
<br />
</div>
);
}
}
// Child2
class Child2 extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
}
handleChange(e) {
this.props.setValue(e.target.value);
}
changeState(text) {
this.setState({ text: text });
}
render() {
return (
<div>
我是child1
<input onChange={this.handleChange.bind(this)} />
<p>来自子组件1的调用: {this.state.text}</p>
<br />
</div>
);
}
}
利用 Context
// 父组件
var Parent = React.createClass({
getChildContext: function() {
return {
changeChildren1: function(text) {
this.refs.cp1.changeState(text);
}.bind(this),
changeChildren2: function(text) {
this.refs.cp2.changeState(text);
}.bind(this)
};
},
childContextTypes: {
changeChildren1: React.PropTypes.func.isRequired,
changeChildren2: React.PropTypes.func.isRequired
},
render: function() {
return (
<div>
<Children1 ref="cp1" />
<Children2 ref="cp2" />
</div>
);
}
});
//子组件1
var Children1 = React.createClass({
getInitialState: function() {
return {
text: ''
};
},
contextTypes: {
changeChildren2: React.PropTypes.func.isRequired
},
changeState: function(text) {
this.setState({ text: text });
},
//输入事件
change: function(event) {
//调用子组件的方法
this.context.changeChildren2(event.target.value);
},
render: function() {
return (
<div>
<p>
<label>子组件1</label>
<input type="text" onChange={this.change} />
</p>
<p>来自子组件2的调用-{this.state.text}</p>
</div>
);
}
});
//子组件2
var Children2 = React.createClass({
getInitialState: function() {
return {
text: ''
};
},
contextTypes: {
changeChildren1: React.PropTypes.func.isRequired
},
changeState: function(text) {
this.setState({ text: text });
},
//输入事件
change: function(event) {
//调用子组件的方法
this.context.changeChildren1(event.target.value);
},
render: function() {
return (
<div>
<p>
<label>子组件2</label>
<input type="text" onChange={this.change} />
</p>
<p>来自子组件1的调用-{this.state.text}</p>
</div>
);
}
});
发布订阅
在 componentDidMount 事件中,如果组件挂载完成,再订阅事件;在组件卸载的时候,在 componentWillUnmount 事件中取消事件的订阅;以常用的发布/订阅模式举例,借用 Node.js Events 模块的浏览器版实现
先引入 node events
模块
yarn add events
在 src 下新建一个 util 目录里面建一个 events.js
import { EventEmitter } from 'events';
export default new EventEmitter();
- components/eventCenter/List1.js
import React, { Component } from 'react';
import emitter from '../../util/events';
class List1 extends Component {
constructor(props) {
super(props);
this.state = {
message: 'List1'
};
}
componentDidMount() {
// 组件装载完成以后声明一个自定义事件
this.eventEmitter = emitter.addListener('changeMessage', message => {
this.setState({
message
});
});
}
componentWillUnmount() {
emitter.removeListener(this.eventEmitter);
}
render() {
return (
<div>
{this.state.message} {this.props.msg}
</div>
);
}
}
export default List1;
- components/eventCenter/List2.js
import React, { Component } from 'react';
import emitter from '../../util/events';
class List2 extends Component {
handleClick = message => {
emitter.emit('changeMessage', message);
};
handleClick2 = message => {
emitter.emit('changeMessageApp', message);
};
render() {
return (
<div>
<button onClick={this.handleClick.bind(this, 'List2')}>
点击我改变List1组件中显示信息
</button>
<button onClick={this.handleClick2.bind(this, 'List2App')}>
点击我改变App组件中显示信息
</button>
</div>
);
}
}
export default List2;
APP.js
import React from 'react';
import './App.css';
import List1 from './components/eventCenter/List1';
import List2 from './components/eventCenter/List2';
import emitter from './util/events';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: 'msgFromApp'
};
}
componentDidMount() {
// 组件装载完成以后声明一个自定义事件
this.eventEmitter = emitter.addListener('changeMessageApp', message => {
this.setState({
message
});
});
}
render() {
return (
<div className="App">
<List1 msg={this.state.message} />
<List2 />
</div>
);
}
}
export default App;
此方法还支持子父组件的传值,但考虑到消息中心的可维护性,易维护性,采用以下的方法
主流通信库
Redux || Mobx