微前端工程之间的通讯

微前端工程之间的通讯


原理

使用发布订阅者模式:一方订阅,一方发布。

使用单例模式:一个工程内使用同一个实例。

微前端加载,首先加载父工程,随后根据配置加载对应的一个或者多个子工程。

父工程先一步生成实例,并传递给子工程。子工程则使用这个实例初始化自己的实例。 共享同一个实例。

代码

import { getState } from "./utils";

let instance: BusInstance | null = null;

class BusInstance {

private queue: Function[] = [];

subscription = (cb: Function) => {

this.queue.push(cb);

};

unsubscription = (cb: Function) => {

this.queue = this.queue.filter((item) => item !== cb);

};

notify = (data: any) => {

this.queue.forEach((cb) => {

if ("[object Function]" === Object.prototype.toString.call(cb)) {

cb(data);

}

});

};

}

export function init(value: BusInstance) {

// 父工程将自己的 bus 实例,传递给子工程

// 子工程调用 init 函数,这样父子工程共享同一个实例

instance = value;

}

export default function Bus() {

// 使用单例模式

// 除了第一次返回的都是同一个实例

if (!instance) {

instance = new BusInstance();

}

return instance;

}

export function subscription(func: Function) {

const bus = Bus();

bus.subscription(func);

}

export function unsubscription(func: Function) {

const bus = Bus();

bus.unsubscription(func);

}

export function notify(data: { type: string; payload: any }) {

const bus = Bus();

// 使用 setTimeout 原因是,防止在 reducer 中调用 notify 函数,导致触发另外一个

reducers

setTimeout(() => {

bus.notify(data);

});

}

export function destory() {

instance = null;

}

export function initGlobal(global: any) {

setTimeout(() => {

const [state, store] = getState();

if (store) {

store.dispatch({ type: "global/initGlobal", payload: global() });

}

});

}

使用以 @umijs/plugin-qiankun 为例

本质上使用 single-spa 用法一致,主要是需要共享实例。

主工程

import Bus from "@static/common/bus";

import { getState, cloneDeep } from "@static/common/utils";

export const qiankun = function () {

return Promise.resolve({

apps: window.SUB_APP_CONFIG.map(({ name, entry, base }) => ({

name,

entry,

base,

props: {

// 父工程生成实例传递给子工程

3 / 5

bus: Bus(),

global() {

const [state] = getState();

if (state) {

return cloneDeep(state.global);

}

return {};

},

},

})),

prefetch: true,

defer: true,

lifeCycles: {

beforeLoad() {

loadingFn(true);

},

beforeMount() {

loadingFn(false);

},

},

});

};

import { Effect, qiankunStart, Reducer } from "umi";

import { getSideOptions, getState } from "@static/common/utils";

import { notify, subscription } from "@static/common/bus";

import globalModel, { GlobalState } from "@static/models/global";

const { namespace, state, reducers, effects, subscriptions } = globalModel;

const newEffects: {

[index: string]: Effect;

} = {

...effects,

*authUserInfo(anyAction, effectsCommandMap) {

if (effects) {

yield effects.authUserInfo(anyAction, effectsCommandMap);

if (window.singleSpaNavigate) {

setTimeout(() => {

qiankunStart();

});

}

}

},

};

const newReduccers: {

[index: string]: Reducer<GlobalState | undefined>;

} = {

...reducers,

updateCollapsed(state, { payload }) {

4 / 5

if (!state) return state;

state.collapsed = payload;

// 发布消息

notify({ type: "global/updateCollapsed", payload });

if (payload) {

state.nav.openKeys = "";

} else {

const { openKeys } = getSideOptions(state.nav.data || []);

state.nav.openKeys = openKeys;

}

state.nav = { ...state.nav };

return { ...state };

},

};

export default {

namespace,

state,

reducers: newReduccers,

effects: newEffects,

subscriptions,

};

子工程

import {

initGlobal,

init,

destory,

subscription,

unsubscription,

} from "@static/common/bus";

import { getState } from "@static/common/utils";

function baseFunc(data: any) {

const [, store] = getState();

if (store) {

const { type, payload } = data;

if ("global/updateCollapsed" === type) {

store.dispatch({ type, payload });

}

}

}

export const qiankun = function () {

if (window.singleSpaNavigate) {

return {

async bootstrap(props: any) {

// 共享实例

init(props.bus);

// 订阅

5 / 5

subscription(baseFunc);

},

async mount(props: any) {

initGlobal(props.global);

},

async unmount() {

// 取消订阅

unsubscription(baseFunc);

destory();

},

};

}

return Promise.resolve();

};

注意:理论上只要共享了实例,可以是父子、兄弟等等之间互相发送消息

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352