actions
一、认识
Actions
通信,是QianKun
官方提供的通信方式。适合业务划分清晰,比较简单的微前端应用,一般来说使用第一种方案就可以满足大部分的应用场景需求。
二、原理
qiankun
内部提供了initGlobalState
方法用于注册MicroAppStateActions
实例用于通信,该实例有三个方法,分别是:
-
setGlobalState
: 设置globalState
- 设置新的值时,内部将执行 浅检查,如果检查到globalState
发生改变则触发通知,通知到所有的 观察者 函数。 -
onGlobalStateChange
: 注册观察者函数 - 响应globalState
变化,在globalState
发生改变时触发该 观察者 函数。 -
offGlobalStateChange
: 取消观察者函数 - 该实例不再响应globalState
变化。
如图所示:
从上图可以看出,我们可以先注册观察者
到观察者池中,然后通过修改globalState
可以触发所有的观察者
函数,从而达到组件间通信的效果。
三、特点
3.1 优点
- 使用简单;
- 官方支持性高;
- 适合通信较少的业务场景;
3.2 缺点
- 子应用独立运行时,需要额外配置无
Actions
时的逻辑; - 子应用需要先了解状态池的细节,再进行通信;
- 由于状态池无法跟踪,通信场景较多时,容易出现状态混乱、维护困难等问题;
四、测试
4.1 主应用
-
通过
vue-cli
脚手架工具创建Vue
主应用vue create main-app
-
设置路由模式为
hash
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home'
Vue.use(VueRouter)
const routes = [
{
name:'Home',
path:'/',
component:Home
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router -
创建
vue.config.js
配置文件,进行配置:a. 配置
publicPath
b. 配置端口号
module.exports = {
// hash 模式下可使用
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/mainApp/',
devServer: {
port: 10001,
},
} -
布局
App.vue
,方便之后切换主应用与子应用a. 安装
element-ui
npm i element-ui -S
b. 布局菜单栏与内容区
注意- 主应用路由容器用
router-view
承载 - 微应用容器用
<div id='childAppContainer></div>
承载,且切记微应用容器ID , 之后配置要用的
<template>
<div id="app">
<el-container>
<el-aside width="200px">
<el-menu
:default-active="activeMenu"
class="el-menu-vertical"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<router-link to="/">
<el-menu-item index="/">
<i class="el-icon-menu"></i><span>首页</span>
</el-menu-item>
</router-link>
<router-link to="/vueChildRouter">
<el-menu-item index="/vueChildRouter">
<i class="el-icon-menu"></i><span>Vue子应用</span>
</el-menu-item>
</router-link>
<router-link to="/reactChildRouter">
<el-menu-item index="/reactChildRouter">
<i class="el-icon-menu"></i><span>React子应用</span>
</el-menu-item>
</router-link>
</el-menu>
</el-aside>
<el-main>
<!-- 主应用容器 -->
<router-view></router-view>
<!-- 子应用容器 -->
<div id="childAppContainer"></div>
</el-main>
</el-container>
</div>
</template>
<script>
export default{
name:'VueMainApp',
data(){
return {
currentMenu:'/',
}
},
computed: {
activeMenu() {
const route = this.$route
const { meta, path } = route
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
}
}
</script>
<style>
html {
margin: 0;
padding: 0;
height: 100%;
}
body {
margin: 0;
padding: 0;
height: 100%;
}
a {
text-decoration: none;
color: #fff;
}
#app {
width: 100%;
height: 100%;
}
.el-container {
height: 100%;
}
.el-menu-vertical {
height: 100%;
}
.el-menu-item.is-active a {
color: #ffd04b !important;
}
.el-main {
margin: 0 !important;
padding: 0 !important;
}
</style> - 主应用路由容器用
-
创建
app.js
,用来配置子应用const apps=[
{
name:'vueChilApp',// 必选,微应用的名称,微应用之间必须确保唯一
entry:'http://localhost:10002',// - 必选,微应用的入口
container:'#childAppContainer',// -必选,微应用的容器节点的选择器或者 Element 实例
activeRule:'/vueChildRouter',// - 必选,微应用的激活规则
props:()=>{return {msg:"Vue 主应用 传给 Vue 子应用的值"}}
},
{
name:'reactChilApp',// 必选,微应用的名称,微应用之间必须确保唯一
entry:'http://localhost:10003',// - 必选,微应用的入口
container:'#childAppContainer',// -必选,微应用的容器节点的选择器或者 Element 实例
activeRule:'/reactChildRouter',// - 必选,微应用的激活规则
props:()=>{return {msg:"Vue 主应用 传给 React 子应用的值"}}
},
]
export default apps; -
创建
qiankun.config.js
,用来配置QianKun
a. 安装
qiankun
依赖npm i qiankun -S
b. 配置
qiankun.config.js
文件import { registerMicroApps, start } from 'qiankun';
import apps from './app';
/**
* @description: 注册子应用
*/
function registerApps() {
registerMicroApps(
apps,
{
beforeLoad: [
loadApp => {
console.log('vue 主应用 正在加载的子应用', loadApp);
},
],
beforeMount: [
mountApp => {
console.log('vue 主应用 正在挂载的子应用', mountApp);
},
],
afterMount: [
mountApp => {
console.log('vue 主应用 挂载完成的子应用', mountApp);
},
],
afterUnmount: [
unloadApp => {
console.log('vue 主应用 卸载完成的子应用', unloadApp);
},
],
},
);
start({
// prefetch: true, // 可选,是否开启预加载,默认为 true。
// sandbox: true, // 可选,是否开启沙箱,默认为 true。//从而确保微应用的样式不会对全局造成影响。
// singular: true, // 可选,是否为单实例场景,单实例指的是同一时间只会渲染一个微应用。默认为 true。
// fetch: () => {}, // 可选,自定义的 fetch 方法。
// getPublicPath: (url) => { console.log(url); },
// getTemplate: (tpl) => { console.log(tpl); },
// excludeAssetFilter: (assetUrl) => { console.log(assetUrl); }, // 可选,指定部分特殊的动态加载的微应用资源(css/js) 不被qiankun 劫持处理
});
}
export default registerApps; -
配置
main.js
入口文件注意- 注册乾坤时需要等到主应用
DOM
加载完成后,所以需要用nextTick
包裹
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import registerApps from './qiankun.config'
Vue.use(ElementUI);
Vue.config.productionTip = false
const MainApp=new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
/**
* @description: 确保装载子应用的容器已创建,我们需要在 new Vue()之后,等DOM加载好了在注册并启动qiankun
*/
MainApp.$nextTick(()=>{
registerApps();
}); - 注册乾坤时需要等到主应用
-
主应用初始化全局状态支池、注册主观察者实现
Actioins
通信a. 主应用注册
MicroAppStateActions
,用来初始化全局状态池/**
* @description: 主应用注册 MicroAppStateActions 实例
*/
import { initGlobalState } from "qiankun";
const initialState = {};
const actions = initGlobalState(initialState);
export default actions;b. 主应用组件中注册观察者,调用
MicroAppStateActions
实例方法,管理状态池<template>
<div class="home">
<h1>QianKun主应用 Home 页面</h1>
<button @click='communication("12adcdfdf")'>主应用通信</button>
</div>
</template>
<script>
import actions from '@/shared/actions';
export default {
name: 'Home',
mounted(){
/**
* @description: 注册一个观察者函数
* * 第一个参数: 回调函数
* * state: 变更后的状态
* * prevState: 变更前的状态
*/
actions.onGlobalStateChange((state,prevState)=>{
console.log(state);
console.log('主应用观察者的 token 改变前的值为:'+prevState.token);
console.log('主应用观察者的 token 改变后的值为:'+state.token);
});
},
methods:{
communication(value='子应用通信'){
actions.setGlobalState({token:value});
}
}
}
</script>
4.2 Vue 子应用
-
通过
vue-cli
脚手架搭建Vue
子应用vue create vue-chil-app
-
设置路由模式为
hash
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
]
/**
* @description: 配置路由
* * base: 路由采用 hash 模式,所以必须配置 base 选项
* * mode: 路由采用 hash 模式
*/
const router = new VueRouter({
base:window.__POWERED_BY_QIANKUN__?'/vueChildRouter':process.env.BASE_URL,
mode:'history',
routes
})
export default router -
创建
vue.config.js
配置文件,进行配置:a. 配置访问路径
publicPath
a. 配置端口号
port
b. 配置跨域
headers
c. 配置打包类型
output
module.exports = {
/**
* @description: 路由采用 hash 模式,需要配置 publicPath 访问路径
*/
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/vueChildRouter/',
/**
* @description: 配置端口号、配置允许本地跨域
* * 配置端口号: 主应用端口号为 10000 , 且主应用中已配置了子应用端口号为 10001 ,所以要保持端口号一致
* * 允许跨域: 本地开发中,端口号不一致,所以要允许跨域
*/
devServer: {
port: 10002,
headers: {
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
/**
* @description: 配置打包文件类型为 umd
* * library: 微应用包名
* * libraryTarget: 将你的 library 暴露为所有的模块定义下都可运行的方式
* * jsonpFunction: 按需加载相关,设置为 webpackJsonp_vueChildApp 即可
*/
output: {
library: `vueChildApp`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_vueChildApp`
}
}
} -
创建
public-path.js
文件if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
} -
配置
main.js
入口文件import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './public-path'
Vue.config.productionTip = false
let instance = null;
/**
* @description: 渲染函数
* 1. router 路由: 采用 hash 模式
* 2. container 容器: #vueChildApp 为 html 模板中挂在应用的 ID ,必须一致且唯一,否则子项目无法独立运行
*/
function render() {
instance = new Vue({
router,
store,
render: h => h(App),
}).$mount('#vueChildApp');
}
/**
* @description: 处理非 QianKun 环境下的渲染,保证独立运行完整
*/
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
/**
* @description: QianKun bootstrap 生命周期
* *特点: bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap
* *作用: 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等
*/
export async function bootstrap () {
console.log('vue 子应用 bootstrap 阶段')
}
/**
* @description: QianKun mount 生命周期
* *特点: 应用每次进入都会调用 mount 方法
* *作用: 通常我们在这里触发应用的渲染方法
*/
export async function mount (props) {
console.log('vue 子应用 mount 阶段')
console.log('vue 子应用 mount 通信',props);
render(props)
}
/**
* @description: QianKun unmount 生命周期
* *特点: 应用每次 切出/卸载 会调用的方法
* *作用: 通常在这里我们会卸载微应用的应用实例
*/
export async function unmount () {
console.log('vue 子应用 unmount 阶段')
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
} -
修改
index.html
注意- 修改
public>index.html
挂载应用的ID,否则子应用无法独立运行
<!DOCTYPE html>
<html lang="">
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="vueChildApp"></div>
<!-- built files will be auto injected -->
</body>
</html> - 修改
-
子应用注册观察者,实现
Actions
通信a. 创建
Actioins
实例/**
* @description: 创建 Actions 实例
*/
function emptyAction() {
console.log("当前使用的 Action 为空!");
}
class Actions {
// 默认值为空 Action
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
};
/**
* 设置 actions
*/
setActions(actions) {
this.actions = actions;
}
/**
* 映射
*/
onGlobalStateChange(...args) {
return this.actions.onGlobalStateChange(...args);
}
/**
* 映射
*/
setGlobalState(...args) {
return this.actions.setGlobalState(...args);
}
}
const actions = new Actions();
export default actions;b. 子应用入口文件中注入
Actions
注意- 主应用是如何与子应用通信的?
答: 主应用挂载子应用时的生命周期为
mount
,mount
函数里面会调用render
函数。我们将主应用的actions
实例在render
函数中注入即可。
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './public-path'
import actions from '@/shared/actions'
Vue.config.productionTip = false
let instance = null;
/**
* @description: 渲染函数
* 1. router 路由: 采用 hash 模式
* 2. container 容器: #vueChildApp 为 html 模板中挂在应用的 ID ,必须一致且唯一,否则子项目无法独立运行
* 3. 运行情况: 主应用在生命周期钩子中运行 / 子应用单独启动时运行
*/
function render(props) {
if(props){
/**
* @description: 注入 actions 实例
* * 说明: 主应用挂在子应用时将会调用 render 方法,所以在 render 方法中将主应用的 actions 示例注入即可。
*/
actions.setActions(props);
}
instance = new Vue({
router,
store,
render: h => h(App),
}).$mount('#vueChildApp');
}
/**
* @description: 处理非 QianKun 环境下的渲染,保证独立运行完整
*/
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
/**
* @description: QianKun bootstrap 生命周期
* *特点: bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap
* *作用: 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等
*/
export async function bootstrap () {
console.log('vue 子应用 bootstrap 阶段')
}
/**
* @description: QianKun mount 生命周期
* *特点: 应用每次进入都会调用 mount 方法
* *作用: 通常我们在这里触发应用的渲染方法
*/
export async function mount (props) {
console.log('vue 子应用 mount 阶段')
console.log('vue 子应用 mount 通信',props);
render(props)
}
/**
* @description: QianKun unmount 生命周期
* *特点: 应用每次 切出/卸载 会调用的方法
* *作用: 通常在这里我们会卸载微应用的应用实例
*/
export async function unmount () {
console.log('vue 子应用 unmount 阶段')
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
}c. 子应用页面注册观察者,并且通过
actioins
实例方法管理全局状态池<template>
<div id="app">
<h1>QianKun Vue 子应用 首页</h1>
<button @click="communication">子应用通信</button>
</div>
</template>
<script>
import actions from "@/shared/actions";
export default {
name: "vueChildApp",
mounted() {
/**
* @description: 注册观察者函数
* * 参数一: 回调函数
* * 参数二: boolean 表示是否立即执行依次观察者函数
*/
actions.onGlobalStateChange((state, prevState) => {
console.log(state);
console.log("子应用观察者的 token 改变前的值为:" + prevState.token);
console.log("子应用观察者的 token 改变后的值为:" + state.token);
}, true);
},
methods: {
communication() {
actions.setGlobalState({ token: "abcdefg" });
},
},
};
</script> - 主应用是如何与子应用通信的?
答: 主应用挂载子应用时的生命周期为
4.3 React 子应用
- 通过
create-react-app
脚手架搭建React
子应用
npx create-react-app react-child-app
-
通过
react-app-rewired
配置Webpack
a. 安装
react-app-rewired
yarn add react-app-rewired -S
b. 创建
config-overrides.js
module.exports = {
/**
* @description: 配置打包文件类型为 umd
* * library: 微应用包名
* * libraryTarget: 将你的 library 暴露为所有的模块定义下都可运行的方式
* * jsonpFunction: 按需加载相关,设置为 webpackJsonp_vueChildApp 即可
*/
webpack: (config) => {
config.output.library = 'reactChildApp'
config.output.libraryTarget = 'umd'
config.output.jsonpFunction = `webpackJsonp_reactChildApp`
config.output.publicPath = process.env.NODE_ENV === 'development' ? '/' : '/reactRouter/';
return config
},
/**
* @description: 配置允许本地跨域
* * 允许跨域: 本地开发中,端口号不一致,所以要允许跨域
*/
devServer: (configFunction) => {
return function(proxy, allowedHost) {
const config = configFunction(proxy, allowedHost)
config.headers = {
'Access-Control-Allow-Origin': '*'
}
config.open = false;
return config
}
}
}c. 配置服务命令
package.json
{
"name": "react-child-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"cra-template": "1.1.2",
"react": "^17.0.2",
"react-app-rewired": "^2.1.8",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3"
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
} -
创建
.env
文件,修改端口PORT=10003
WDS_SOCKET_PORT=10003 -
创建
public-path.js
文件if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
//__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
} -
配置
index.js
入口文件import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import "./public-path";
/**
* @description: 渲染函数
* 1. container 容器: #vueChildApp 为 html 模板中挂在应用的 ID ,必须一致且唯一,否则子项目无法独立运行
*/
function render(){
ReactDOM.render(<App />,document.getElementById('reactChildApp'));
}
/**
* @description: 处理非 QianKun 环境下的渲染,保证独立运行完整
*/
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
/**
* @description: QianKun bootstrap 生命周期
* *特点: bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap
* *作用: 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等
*/
export async function bootstrap() {
console.log("ReactMicroApp bootstraped");
}
/**
* @description: QianKun mount 生命周期
* *特点: 应用每次进入都会调用 mount 方法
* *作用: 通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
console.log("ReactMicroApp mount", props);
render(props);
}
/**
* @description: QianKun unmount 生命周期
* *特点: 应用每次 切出/卸载 会调用的方法
* *作用: 通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
console.log("ReactMicroApp unmount");
ReactDOM.unmountComponentAtNode(document.getElementById("reactChildApp"));
} -
修改
index.html
注意- 修改
public>index.html
挂载应用的ID,否则子应用无法独立运行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="reactChildApp"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html> - 修改
-
子应用注册观察者,实现
Actions
通信a. 创建
Actioins
实例/**
* @description: 创建 Actions 实例
*/
function emptyAction() {
console.log("当前使用的 Action 为空!");
}
class Actions {
// 默认值为空 Action
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
};
/**
* 设置 actions
*/
setActions(actions) {
this.actions = actions;
}
/**
* 映射
*/
onGlobalStateChange(...args) {
return this.actions.onGlobalStateChange(...args);
}
/**
* 映射
*/
setGlobalState(...args) {
return this.actions.setGlobalState(...args);
}
}
const actions = new Actions();
export default actions;b. 子应用入口文件中注入
Actions
::: warning 细节
- 主应用是如何与子应用通信的?
答: 主应用挂载子应用时的生命周期为
mount
,mount
函数里面会调用render
函数。我们将主应用的actions
实例在render
函数中注入即可。 :::
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import "./public-path";
import actions from './shared/actions'
/**
* @description: 渲染函数
* 1. router 路由: 采用 hash 模式
* 2. container 容器: #reactChildApp 为 html 模板中挂在应用的 ID ,必须一致且唯一,否则子项目无法独立运行
* 3. 运行情况: 主应用在生命周期钩子中运行 / 子应用单独启动时运行
*/
function render(props){
if(props){
/**
* @description: 注入 actions 实例
* * 说明: 主应用挂在子应用时将会调用 render 方法,所以在 render 方法中将主应用的 actions 示例注入即可。
*/
actions.setActions(props);
}
ReactDOM.render(<App />,document.getElementById('reactChildApp'));
}
/**
* @description: 处理非 QianKun 环境下的渲染,保证独立运行完整
*/
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
/**
* @description: QianKun bootstrap 生命周期
* *特点: bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap
* *作用: 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等
*/
export async function bootstrap() {
console.log("ReactMicroApp bootstraped");
}
/**
* @description: QianKun mount 生命周期
* *特点: 应用每次进入都会调用 mount 方法
* *作用: 通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
console.log("ReactMicroApp mount", props);
render(props);
}
/**
* @description: QianKun unmount 生命周期
* *特点: 应用每次 切出/卸载 会调用的方法
* *作用: 通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
console.log("ReactMicroApp unmount");
ReactDOM.unmountComponentAtNode(document.getElementById("reactChildApp"));
}c. 子应用页面注册观察者,并且通过
actioins
实例方法管理全局状态池import actions from './shared/actions';
import React, {useEffect} from 'react';
function communication(){
actions.setGlobalState({token:'123456789'});
}
function App() {
useEffect(()=>{
/**
* @description: 注册观察者函数
* * 参数一: 回调函数
* * 参数二: boolean 表示是否立即执行依次观察者函数
*/
actions.onGlobalStateChange((state,prevState)=>{
console.log(state);
console.log('子应用观察者的 token 改变前的值为:'+prevState.token);
console.log('子应用观察者的 token 改变后的值为:'+state.token);
},true);
});
return (
<div className="App">
<h1>QianKun React 子应用 首页</h1>
<button onClick={()=>{communication()}}>子应用通信</button>
</div>
);
}
export default App; - 主应用是如何与子应用通信的?
答: 主应用挂载子应用时的生命周期为