1、react 通信
react的数据流是单向的, react 通信有以下几种方式:
单向数据流:指当前组件的 state 以 props 的形式流动时只能流向组件树中比自己层级更低的组件
- 父向子通信:父组件提供state,并且内部设置好数据,子组件中通过 props 接收父组件中传递的数据
- 子向父通信:父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件传过来的值
- 父向孙通信:利用context传值。React.createContext()
- 兄弟间通信:
- 找一个相同的父组件,既可以用props传递数据,也可以用context的方式来传递数据。
- 用一些全局机制去实现通信,比如redux等
- 发布订阅模式
问题:利用props传递数据单层之间传递很方便,可是遇到多层传递就会比较麻烦,那么怎样解决多层传递的问题那? -----> 发布订阅模式
2、发布订阅模式
组件间通信需要引用一个类的实例,使用单例模式实现。
在 发布/订阅模式 有 发布者 和 订阅者,它们通过信道链接到一起。其主要包含三个对象:
订阅者:
订阅一个或者多个信道消息的对象。
发布者:
消息的发布者,往信道中投递消息的对象。
信道:
每个信道都有一个名字,信道的实现细节对用户代码来说是隐藏的。
3、订阅 / 发布模型API设计思路
on():
负责注册事件
的监听(订阅),指定事件触发(发布)时的回调函数;emit():
负责触发事件
,可以通过传参使其在触发的时候携带数据off():
负责监听器的删除(解除事件
)
事件和监听函数的对应关系
constructor(){
//eventMap 用来存储事件和监听函数之间的关系
this.eventMap={}
}
实现订阅
//type 代表事件的名称
on(type,handler){
//handler 必须是一个函数,如果不是直接报错
if(!(handler instanceof Function)){
throw new Error("请重新上传参数")
}
//判断type事件对应的队列是否存在
if(!(this.eventMap[type]){
//若不存在,新建该队列
this.eventMap[type]=[]
//若存在,直接往队列里推入handler
this.eventMap[type].push(handler)
})
}
实现发布
//触发时可以携带数据,params就是数据的载体
emit(type.params){
//假设该事件是有订阅的(对应的事件队列存在)
if(this.eventMap[type]){
//将事件队列里的handler依次执行出队
this.eventMap[type].forEach((handler,index)=>{
//注意别忘了读取params
handler(params)
})
}
}
//解除绑定
off(type,handler){
if(this.eventMap[type]){
this.eventMap[type].splice(this.eventMap[type].indexOf(handler)>>>0,1)
}
}
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
class myEventEmitter{
constructor(){
//eventMap 用来存储事件和监听函数关系
this.eventMap={};
}
// 1.on注册事件监听器
on(type,handler){
//type 代表事件的名称,handler 必须是一个函数,如果不是直接报错
if(!(handler instanceof Function)){
throw new Error("请重新上传参数")
}
//判断type事件对应的队列是否存在
if(!this.eventMap[type]){
//若不存在,新建该队列
this.eventMap[type]=[];
console.log("注册成功");
}else{
//若存在,直接往队列里推入handler
this.eventMap[type].push(handler)
}
}
// 2.如何发布
emit(type,params){ //params携带数据
//假设该事件是有订阅,即存在对应的事件队列
if(this.eventMap[type]){
//将事件队列里的handler依次执行出队
this.eventMap[type].forEach((handler,index)=>{
//需要读取params
handler(params)
});
console.log('发布成功');
}
}
//解除绑定
off(type,handler){
if(this.eventMap[type]){
this.eventMap[type].splice(this.eventMap[type].indexOf(handler)>>>0,1); //>>>无符号向右移动符
}
console.log("解除成功");
}
}
//测试代码
//实例化myEventEmitter
const myEvent = new myEventEmitter();
//写handler
const testHandler = function(params){
console.log(`test事件被触发了,testHandler接收到的入参是${params}`);
};
//监听test事件
myEvent.on("test",testHandler);
//触发test事件的同时,传入希望testHandler感知的参数
myEvent.emit("test",testHandler("newState"));
//解除
myEvent.off("test",testHandler);
</script>
</body>
</html>
结果展示
4、观察者模式
在这种模式中,一个目标对象(被观察者)管理所有的依赖于它的对象(观察者),并且在它本身的状态发生变化的时候主动发出通知。
其主要包含两个对象:
被观察者和观察者
缺点
耦合问题:每个观察者必须和被观察对象绑定在一起,这引入了耦合
性能问题:在最基本的实现中观察对象必须同步地通知观察者。这可能会导致性能瓶颈。