前言
人生是个积累的过程,你总会有摔倒,即使跌倒了,你也要懂得抓一把沙子在手里。 —— 丁磊
码过的每一个需求、踩过的每一个坑、修过的每一个 bug
、学过的每一个知识以及看过的每一篇文章都不会成为无用功,它们都将为自己的技术城堡添砖加瓦。今天我们将从实现不同的 React、Vue App
之间的状态共享这个需求着手,学习 React
、Vue
中那些我们很少用到,但是一旦遇到这些特殊的需求就非它莫属的特性 🤹🏻
需求 & 问题
需求现状
我在字节的日常业务开发中,我需要将不同的业务组件挂载在一个不属于我们接管的平台页面中,由于每个业务组件都有各自不同的挂载位置和时机,并且都可以看做一个单独的 React
应用,所以我们用 Webpack
进行多入口打包,打出多个 React
应用,然后在这个页面通过引入 sdk
的方式挂载业务组件。
问题
多入口打包这样的做法会导致业务组件内部状态可以共享,但是各个业务组件之间的状态无法很好的共享。并且每个组件内部可能需要相同的数据,所以会导致相同的网络请求会在同一个页面发送多次的情况。
所以我们面临问题以及最终目的就是解决多个 React
应用之间的状态共享:
- 某个状态需要在多个挂载在页面不同
DOM
节点的业务组件间共享(访问 + 更新) - 某组件内交互需要触发其他组件的状态更新
解决方案
一、将状态挂载在全局 window 对象、EventEmitter
触发更新
使用类继承 EventEmitter
通过在类中申明公共变量来进行存储和共享数据,使用事件订阅发送的方式来实现数据共享以及更新。使用单例模式同步在 window
中,以实现多个组件使用同一个发布订阅实例,来同步和共享数据。EventEmitter
我们直接使用 eventemitter3 库提供的 on
监听事件以及emit
触发事件。以下是 TS Demo
代码
import EventEmitter from 'eventemitter3'
// 定义触发的事件常量
export const ACTION = {
ADD_COUNT: 'add-count',
} as const
// 申明 Store 接口
export interface IStore {
count: {
value:number,
addCount:() => void
}
}
// 通过继承 EventEmitter 的 class 中声明 store 来存储数据
export class MyEmitter extends EventEmitter {
public store: IStore = {
count:{
value:1,
addCount:()=>{
th