主要探究下主应用和多个微应用之间如何使用Vuex来进行状态管理,这其实是对上一篇文章中通信方式第二种方式的补充,因为 vue 主要还是使用 vuex 作为状态管理。
一、场景选择
1、项目现状:
- 主应用是Vue技术栈,使用Vuex进行状态管理
- 多个微应用也是Vue技术栈,并且都可能使用Vuex进行状态管理
2、想要解决的问题:
- 主应用与微应用的通信
- 微应用之间的通信
3、通信方式的选择:
qiankun
官方提供的通信方式 -Actions
通信 (不多说,看上篇文章即可);- 使用shared实例通信,使用Vuex进行状态管理
- 子应用无法随意污染主应用的状态池,只能通过主应用暴露的
shared
实例的特定方法操作状态池,从而避免状态池污染产生的问题。 - 子应用将具备独立运行的能力
二、核心思想
三、具体实现
(一)微应用原本就没有使用Vuex
进行状态管理
1、主应用向微应用传递store
实例
registerMicroApps([
{
name: "chai-project",
entry: "//localhost:8080",
container: '#yourContainer',
activeRule: "/micro",
props: {
store //共享主应用的store实例
}
}
])
2、微应用使用主应用共享的store实例
针对第一种情况,就是在入口文件中引入vuex
,并使用该插件,进而在创建vue
实例的时候,传入主应用共享的store
实例。
import Vuex from 'vuex'
Vue.use(Vuex);
function render (props) {
const store = props.store;
// 在 render 中创建 VueRouter,可以保证在卸载微应用时,移除 location 事件监听,防止事件污染
router = new Router({
// 运行在主应用中时,添加路由命名空间 /micro
base: window.__POWERED_BY_QIANKUN__ ? '/micro' : '/',
mode: 'history',
routes
});
// 挂载应用
instance = new Vue({
router,
store,//主应用共享的store实例
render: (h) => h(App)
}).$mount('#app');
}
3、验证主应用和微应用之间是否可以完成通信,状态同步。
验证的思路就是:在主应用和微应用的页面上添加改变同一个state
的方法,并且利用computed
实时显示该state
的状态值。
验证用例主要是:
- 点击主应用按钮,修改
state
值之后,主应用和微应用的页面上都实时触发computed
属性,展示最新状态值 - 点击微应用按钮,修改
state
值之后,主应用和微应用的页面上都实时触发computed
属性,展示最新状态值
验证的结果:不论是点击主应用的按钮,还是点击微应用的按钮,主应用的computed
属性成功被触发,微应用始终未能正常监听到状态值得改变,computed
属性从未被触发。
4、bug修复:
微应用的computed
始终没有被触发,底层原因就是其依赖属性this.$store.state.count
是非响应式的,这会导致难以触发。
Vuex
正常使用的时候,所有的状态值都是响应式的(需要主动在 state 里声明的才是响应式的),可以直接用于Vue
页面之中,但是这里是非响应式的,导致这个的原因其实十分简单。
这里的store
实例是由主应用传递过来的,store
中的状态对于主应用的Vue
实例而言是亲儿子,是响应式的,在微应用中,虽然可以使用共享store
实例中的commit
方法,但是对于微应用的Vue
实例而言,不是亲儿子,是非响应式的,这样分析之后,解决方案就十分明确:在微应用中将共享的store实例进行响应式设置,这是Vue现有的API方法Vue.observable(store)。
如此处理之后,不论主应用还是微应用中,修改共享store
的state
状态值,在主应用和微应用中都能够实时感知,并对其做出响应的反馈。
(二)微应用本身就有自己store
实例
这种情况主要考虑的是两种方案:
-
主应用需要提前得知子应用的
store
内容,将其与主应用的store进行某种融合,这样子应用在集成环境中以及在独立运行时都能够正常运行。缺点:这方方案会导致主应用和子应用相互耦合过强,并且主应用和子应用都要维护一份子应用的
store
,增加工作量,过于笨重。 -
主应用依旧只传递主应用的
store
,子应用的store依旧在使用,也就是在子应用中既可以操作主应用的store
,也可以操作子应用的store
。优点:主应用只需关注需要交互的状态即可,不用关心子应用原本的
store
内容。子应用也只需关注自己的store
内容即可,降低耦合,减轻复杂度。
这里基于父应用已经共享自己的store
,并且主应用和子应用之间已经能够完成对于主应用的state
状态变化的响应。
考虑如何在子应用中使用两个store
,new Vue()
中目前注入的是主应用的store
,那子应用本身的store
如何全局注册呢?仔细思考后,其实很简单,只需要在入口文件中添加如下一行代码:
Vue.prototype.microStore = microStore;
如此一来,在子应用的各个页面都能够通过this.microStore
访问自身的store
。
computed: {
microCount: {
get (){
return this.microStore.state.microCount;
}
}
}
主要来自于对下面这篇文章的学习,也是在查询微前端应用间通信方案时看到的,是对上一篇文章的补充。起初使用微前端时看的不是很能清晰理解,昨天自己在项目中实战主子应用间通信成功之后再回过头来看这篇文章,确实就清晰多了:《基于qiankun的微前端最佳实践-通信篇(Vuex)- https://www.jianshu.com/p/b2a77373c09e》