微前端的三种通信方式

直入主题,在微前端项目的开发过程中,我主要使用3种通信方式,按照易用程度排序为:

  1. location.query
  2. sessionStorage
  3. props

在普通组件开发过程中,这也是常用的父子组件通信方式,只是它们与微前端发生的化学反应要更加剧烈。

location.query

将参数存在url中,这种方式有几个好处。

  1. 页面与参数高度匹配,不需要考虑离开页面时参数清理的问题。
  2. 可直接通过URL分享指定页面与内容,减少使用者间的沟通成本(比如可以跳转至指定tab页,或者表格的指定页数和搜索参数)。
  3. 浏览器历史即是操作历史,在返回时可直接调用goBack()方法,不需要记录上一个页面的参数。

缺点:

  1. URL不美观,数据存量有极限。
  2. 数据有一定的时效性,譬如刷新时按照query请求数据,其中的参数可能已经无效。
    3fn7.webp

sessionStorage

相较于location.query来说,它的优点是:

  1. URL美观,不易被使用者察觉和破坏。
  2. 可以存储的数据量大。

缺点:

  1. 操作繁多,需要字符串与对象间的转换。
  2. 需要考虑页面进出时的数据清理问题。
  3. 不具有url分享的属性。
    3kSw.webp

props

不好用,我能不用就不用。
在我参与的前端项目开发中,使用的是umi框架内置的微前端,也就是qiankun。
它提供了三种微前端嵌入方式,分别是:

  1. 路由绑定引入
  2. <MicroApp /> 组件引入子应用。
  3. <MicroAppWithMemoHistory /> 组件引入子应用。
    在开发某个特性时,需要在子应用的子组件中再嵌入一个应用(姑且称为孙应用)。
    由于主应用和子应用已经使用了query进行跳转和参数传递,所以孙应用不方便再使用query。
    与此同时,孙应用需要与子应用的子组件进行切换显示,并且孙应用本身也需要根据额外参数来控制内容。
    3uBn.webp
    这下不得不使用<MicroAppWithMemoHistory />引入孙应用,并通过props来传递参数,但问题也随之而来:

问题

  1. 在原有项目中添加“被嵌入”兼容时,所需内容有的为一整个页面,有的为小组件,需要重构。
  2. umi中,子应用使用useModel来使用props参数,原本的数据请求逻辑直接使用。
  3. props中数据请求参数变动时会导致多次请求/微前端重载。

解决方案

1. 使用单一路由、单一页面,在页面中进行内容控制

无论是什么内容,本质都是组件,将它们以组件的形式全部引入统一页面中。
此时子应用加载孙应用时只需要使用一个url:<MicroAppWithMemoHistory name="app2" url="/onlyone" {...props} />,仅通过props对孙应用内容进行控制。
在孙应用中根据props加载不同组件即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const MicroApp=({
type //加载什么组件
}:Props)=> {
if(type==='1'){
return <Component1/>
}
if(type==='2'){
return <>
<Component2/>
<Page1/>
</>
}
return '参数错误'
}

2. 在孙应用控制页面中对组件添加用于指示当前应作为微前端的参数

比如说为每个内容组件传递isMicroApp这个参数来告诉该组件应该以useModel中的参数作为请求参数,而不用更改原本的请求逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// MicroApp.tsx
const MicroApp=({
type //加载什么组件
}:Props)=>{
if(type==='1'){
return <Component1 isMicroAPP />
}
return '参数错误'
}

// Component1.tsx
const Component=({
isMicroApp,
query
}:Props)=>{
const query = isMicroApp ? useModelQuery : query;
......
}

3. 一般父子组件使用props传值也会遇到的问题

原本组件中就使用useEffect调用请求参数的话,这个问题应该已经有相应的处理逻辑了。
而如果原本组件中的请求参数来自于location.query,我们不仅要添加问题2中类似的参数获取方式,还要添加额外的逻辑防止多次请求。