非嵌套组件间通信
非嵌套组件,就是没有任何包含关系的组件,包括兄弟组件以及不在同一个父级中的非兄弟组件。对于非嵌套组件,可以采用下面两种方式:
- 利用二者共同父组件的 context 对象进行通信
- 使用自定义事件的方式
如果采用组件间共同的父级来进行中转,会增加子组件和父组件之间的耦合度,如果组件层次较深的话,找到二者公共的父组件不是一件容易的事,当然还是那句话,也不是不可以...
这里我们采用自定义事件的方式来实现非嵌套组件间的通信。
我们需要使用一个 events 包:
npm install events --save
新建一个 ev.js,引入 events 包,并向外提供一个事件对象,供通信时使用:
import { EventEmitter } from "events";
export default new EventEmitter();
App.js:
import React, { Component } from 'react';
import Foo from "./Foo";
import Boo from "./Boo";
import "./App.css";
export default class App extends Component{
render(){
return(
<div>
<Foo />
<Boo />
</div>
);
}
}
Foo.js:
import React,{ Component } from "react";
import emitter from "./ev"
export default class Foo extends Component{
constructor(props) {
super(props);
this.state = {
msg:null,
};
}
componentDidMount(){
// 声明一个自定义事件
// 在组件装载完成以后
this.eventEmitter = emitter.addListener("callMe",(msg)=>{
this.setState({
msg
})
});
}
// 组件销毁前移除事件监听
componentWillUnmount(){
emitter.removeListener(this.eventEmitter);
}
render(){
return(
<div>
{ this.state.msg }
我是非嵌套 1 号
</div>
);
}
}
Boo.js:
import React,{ Component } from "react";
import emitter from "./ev"
export default class Boo extends Component{
render(){
const cb = (msg) => {
return () => {
// 触发自定义事件
emitter.emit("callMe","Hello")
}
}
return(
<div>
我是非嵌套 2 号
<button onClick = { cb("blue") }>点击我</button>
</div>
);
}
}
自定义事件是典型的发布/订阅模式,通过向事件对象上添加监听器和触发事件来实现组件间通信。