前言
- Pubsubjs 是一个用 JavaScript 编写的基于主题的发布/订阅库。
- Pubsubjs 具有同步解耦功能,因此主题是异步发布的。 这有助于保持程序的可预测性,因为在使用者处理主题时,主题的发起者不会被阻塞。
- Pubsubjs 被设计为在单个进程中使用,并不适合多进程应用程序(比如具有许多子进程的 Node.js-Cluster)。 如果你的 Node.js 应用程序是一个单进程应用程序,你很好。 如果它是(或将是)一个多进程应用程序,你最好使用 redis pub / sub 或类似的应用程序
一、PubSub使用方式
- react导入库 npm install pubsub-js --save
- react 页面引入pubsubjs import PubSub from 'pubsub-js'
- pubsubjs使用 发送消息:PubSub.publish(名称,参数) 订阅消息:PubSub.subscrib(名称,函数) 取消订阅:PubSub.unsubscrib(名称)
// Publish some topics 发布主题
PubSub.publish('car.purchase', {name: 'my new car'});
PubSub.publish('car.drive', {speed: '14'});
PubSub.publish('car.sell', {newOwner: 'someone else'});
var myToplevelSubscriber = function (msg, data) {
console.log('top level: ', msg, data);
}
//订阅主题
PubSub.subscribe('car', myToplevelSubscriber);//myToplevelSubscriber是一个函数
var mySpecificSubscriber = function (msg, data) {
console.log('specific: ', msg, data);
}
PubSub.subscribe('car.drive', mySpecificSubscriber);
- 使用”常量”的例子
// event-types.js
export const MY_TOPIC = Symbol('MY_TOPIC')
// somefile.js
import { MY_TOPIC } from './event-types.js'
PubSub.subscribe(MY_TOPIC, function (msg, data) {
console.log(data)
});
PubSub.publish(MY_TOPIC, 'world');
二、React实例使用监听实现传参(实际上是子传父的时候用的,因为父传子是有props的,个人观点)
- 子页面home.js使用PubSub.publish发送state
import React, { Component } from 'react';
import PubSub from 'pubsub-js';
class Home extends Component {
constructor(props){
super(props);
this.state={
increase:'increase',
decrease:'decrease'
}
}
buttonIncrease(){
PubSub.publish('PubSubmessag',this.state.increase);
}
buttonDecrease(){
PubSub.publish('PubSubmessage', this.state.decrease);
}
render() {
return (
<div>
Some state changes:
<button onClick={this.buttonIncrease.bind(this)}>Increase</button>
<button onClick={this.buttonDecrease.bind(this)}>Decrease</button>
</div>
)
}
}
export default Home;
- 父页面App.js接收使用PubSub.subscribe订阅指定消息,PubSub.unsubscribe取消订阅消息
import React, { Component } from 'react';
import { Link} from 'react-router-dom';
import PubSub from 'pubsub-js';
export default class App extends Component{
constructor(props){
super(props);
this.state={
increase:'none',
}
}
componentDidMount(){
this.pubsub_token = PubSub.subscribe('PubSubmessage', function (topic,message) {
this.setState({
increase: message
});
}.bind(this));
}
componentWillUnmount(){
PubSub.unsubscribe(this.pubsub_token);
}
render() {
return (
<div>
<header>
Links:
<Link to="/App/home">Home</Link>
</header>
<div style={{ marginTop: '1.5em' }}>{ this.props.children}</div>
<div style={{ marginTop: '1.5em' }}>{ this.state.increase}</div>
</div>
)
}
}
当在子页面单击increase、decrease按钮,会发送不同的消息给父页面,父页面收到消息,利用this.state.increase进行呈现,此时你会发现它是实时变化的,因为它会实时监听子组件发送的消息。
- 另外方法解决问题:React-Router4.0建立子父组件关系,取代pubsub
子父组件关系建立是依靠React-Router4.0来建立的,附上子父组件关系的源码,若对RR4.0不太了解,可参考http://blog.csdn.net/zfan520/article/details/78563034
import React, { Component } from 'react';
import {BrowserRouter } from 'react-router-dom';
import { Router, Route, } from 'react-router'
import App from '../components/App.js'
import Home from '../components/Home.js'
export default class RouterIndex extends Component {
render() {
return (
<BrowserRouter>
<App path="/App" component={App}>
<Route path="/App/home" component={Home} />
</App>
</BrowserRouter>
)
}
}
原文链接:blog.csdn.net/zfan520/art…
三、实际应用一(aqmap 的react应用)
- 点击直观打开按钮,将状态发布出去
PubSub.publish(NavModuleAirmapModels.pubSubDict.toggleShowTextLayer.topic,{isShow:!this.state.showTextLayer});
//NavModuleAirmapModels当前模块,并且发布跟订阅的地方是一个model里面的topic,重点传参只能穿一个参数
pubSubDict/toggleShowTextLayer/topic的定义
const pubSubDict={
// 切换直观
toggleShowTextLayer:{token:null,topic:pubSubTopic+".toggleShowTextLayer"},
}
2.nav-module-airmap.js 订阅状态并调用函数
models.pubSubDict.toggleShowTextLayer.token =PubSub.subscribe(models.pubSubDict.toggleShowTextLayer.topic,this.onToggleShowTextLayer.bind(this));
//直观textlayer,并且订阅的页面里要把发布的JS中NavModuleAirmapModels定义的model.js引入到这个JS中,这样才能保证订阅跟发布的地方是一个topic,这是重点才能保证订阅的是一个地方
一定要注意就是订阅的地方必须是跟自己相关的不能照抄,硬抄
四、实际应用二(aqmap 的react应用)
1.将resize事件发布出去,在最高级的页面layout.js
componentDidMount () {
//监听窗口大小改变
window.addEventListener('resize', this.handleResize.bind(this)); //监听窗口大小改变
}
componentWillUnmount () {
window.removeEventListener('resize',deskDivWidth,deskHeight);//取消监听
}
// 自适应浏览器的高度
handleResize = () => {
this.setState({
deskDivWidth: document.body.clientWidth,
deskHeight: document.body.clientHeight,
});
PubSub.publish(models.pubSubDict.moduleResize.topic); //resize仅仅发布的topic这个状态
}
2.airmap订阅的地方
PubSub.subscribe(LayoutModels.pubSubDict.moduleResize.topic,this.onHandleResize.bind(this)); //resize,import的地方定义了这个类LayoutModels,名字不用必须跟发布的地方是一样,但是表达的字符串必须是同一个
//监听resize事件
onHandleResize(){
setTimeout(()=>{
this.airLayer.canvasText.width = this.map.getSize().width;
this.airLayer.canvasText.height = this.map.getSize().height;
if(this.textLayer.isShow){//alert(this.textLayer.amapCustomLayer.show());
this.textLayer.amapCustomLayer.show();
this.textLayer.layer.update(this.textLayer.data);
}
}, 5000);
}
3.代码开始写成这样,就会自动到登录的页面了,那是因为逻辑有问题
componentDidMount () {
//监听窗口大小改变
window.addEventListener('resize', this.handleResize.bind(this)); //监听窗口大小改变
PubSub.publish(models.pubSubDict.moduleResize.topic); //resize,publish的位置写的不对
}
// 自适应浏览器的高度
handleResize = () => {
this.setState({
deskDivWidth: document.body.clientWidth,
deskHeight: document.body.clientHeight,
});
}
这样会造成发布的状态,根本传递不过去
4.pubsub 一个地方发布 多个地方订阅,只得是不能功能模块,如果是同一个功能模块去订阅,只有一个地方管用其他的地方是不管用的