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]=[]//若存在,直接往队列里推入handlerthis.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{//若存在,直接往队列里推入handlerthis.eventMap[type].push(handler)}}// 2.如何发布emit(type,params){ //params携带数据//假设该事件是有订阅,即存在对应的事件队列if(this.eventMap[type]){//将事件队列里的handler依次执行出队this.eventMap[type].forEach((handler,index)=>{//需要读取paramshandler(params)});console.log('发布成功');}}//解除绑定off(type,handler){if(this.eventMap[type]){this.eventMap[type].splice(this.eventMap[type].indexOf(handler)>>>0,1); //>>>无符号向右移动符}console.log("解除成功");}}//测试代码//实例化myEventEmitterconst myEvent = new myEventEmitter();//写handlerconst 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、观察者模式
在这种模式中,一个目标对象(被观察者)管理所有的依赖于它的对象(观察者),并且在它本身的状态发生变化的时候主动发出通知。
其主要包含两个对象:
被观察者和观察者
缺点
耦合问题:每个观察者必须和被观察对象绑定在一起,这引入了耦合
性能问题:在最基本的实现中观察对象必须同步地通知观察者。这可能会导致性能瓶颈。



















