pubsub 所有介绍

5,290 阅读4分钟

前言

  1. Pubsubjs 是一个用 JavaScript 编写的基于主题的发布/订阅库。
  2. Pubsubjs 具有同步解耦功能,因此主题是异步发布的。 这有助于保持程序的可预测性,因为在使用者处理主题时,主题的发起者不会被阻塞。
  3. Pubsubjs 被设计为在单个进程中使用,并不适合多进程应用程序(比如具有许多子进程的 Node.js-Cluster)。 如果你的 Node.js 应用程序是一个单进程应用程序,你很好。 如果它是(或将是)一个多进程应用程序,你最好使用 redis pub / sub 或类似的应用程序

一、PubSub使用方式

  1. react导入库 npm install pubsub-js --save
  2. react 页面引入pubsubjs import PubSub from 'pubsub-js'
  3. 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);
  1. 使用”常量”的例子
// 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的,个人观点)

  1. 子页面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;
  1. 父页面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进行呈现,此时你会发现它是实时变化的,因为它会实时监听子组件发送的消息。

  1. 另外方法解决问题: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应用)

  1. 点击直观打开按钮,将状态发布出去
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 一个地方发布 多个地方订阅,只得是不能功能模块,如果是同一个功能模块去订阅,只有一个地方管用其他的地方是不管用的