qiankun实现应用间通信

主应用vue3 + vite

子应用1: Vue3 + vite github.com/huzhushan/v...

子应用2: Create React App + Webpack

通过vuex/pinia实现通信

第一步:在主应用中创建一个store

src/store/index.ts

js 复制代码
const personModule = {
  state: {
    id: 0,
    name: '',
    age: 0
  },
  mutations: {
    setId(state: Object, id: number) {
      state.id = id
    },
    setName(state: Object, name: string) {
      state.name = name
    },
    setAge(state: Object, age: number) {
      state.age = age
    }
  },
  actions: {
    setId(context: Object, id: number) {
      context.commit('setId', id)
    },
    setName(context: Object, name: string) {
      context.commit('setName', name)
    },
    setAge(context: Object, age: number) {
      context.commit('setAge', age)
    }
  }
}

export default new Vuex.Store({
  state: {
    
  },
  getters: {},
  mutations: {

  },
  actions: {

  },
  modules: {
    personModule
  }
})

第二步:在main.js文件中引入这个store,并通过RegistrableAppprops传给子应用

js 复制代码
import store from './store/index'
import { registerMicroApps, start, initGlobalState } from 'qiankun'

registerMicroApps([
  {
    name: 'vue3-element-admin',
    entry: '//localhost:3001',
    container: '#container',
    activeRule: '/#/vue3-element-admin',
    props: {
      store,
    }
  }
],
)

第三步:在子应用的main.js文件中接收这个store,并通过createApp()的第二个参数props,将主应用的这个store传递到子应用的根组件App.vue中。

js 复制代码
renderWithQiankun({
    mount(props) {
      appMount(props);
    },
    //、、、
})

function appMount(props) {
  app = createApp(App, {
    parentStore: props.store
  })
}

第四步:在子应用的根组件App.vue文件中,通过props接收这个store,并通过provite()将这个store注入到所有子组件中

js 复制代码
export default defineComponent({
  props: {
    parentStore: Object
  },
  setup(props) {
    const { lang } = useLang()
    provide('parentStore', props.parentStore)
    //、、、
  }
 })

第五步:在需要的子组件中,通过inject()接收这个store,并根据需要操作这个store

js 复制代码
<script setup>
  import { onMounted, onUnmounted , onActivated, onDeactivated, inject }   from 'vue';
  const parentStore = inject('parentStore')
  const personModule = parentStore.state.personModule
  const changeParentStore = () => {
    parentStore?.dispatch('setId', '11')
    parentStore?.dispatch('setName', 'lily')
    parentStore?.dispatch('setAge', 18)
  }
 </script>

通过vuex创建的store也可以在react子应用中使用

子项目Create-React-App + webpack

第一步,在入口处接收store, 然后传递给根组件

js 复制代码
let root;
function render(props) {
  const rootProps = {
    parentStore: props.store
  }
  root = ReactDOM.createRoot(props?.container ? props.container.querySelector('#root') : document.querySelector('#root'));
  root.render(
    <React.StrictMode>
      <App { ...rootProps  } /> //将store传递给根组件
    </React.StrictMode>
  );
}

export async function mount(props) {
  render(props)
}

第二步:在根组件或其他子组件中使用store

js 复制代码
function App(props) {
  const parentStore = props?.parentStore
  const personModule = props?.parentStore?.state?.personModule
  const changeParentStore = () => {
    parentStore.commit('setId', 11)
    parentStore.commit('setName', 'Lucy')
    parentStore.commit('setAge', 18)
    forceRemount()
  }

  const [key, setKey] = useState(0);
  // 当需要强制重新渲染时,调用这个函数
  const forceRemount = () => {
    setKey(currentKey => currentKey + 1);
  };
  return (
    <div>
      <div>展示主应用vue传过来的store:{personModule?.id}</div>
      <div>展示主应用vue传过来的store:{personModule?.name}</div>
      <div>展示主应用vue传过来的store:{personModule?.age}</div>
      <div>
          <Button type='primary' onClick={changeParentStore}>
            修改主应用的store
          </Button>
      </div>
  </div>
  )

通过EventBus实现通信

第一步:在主应用中创建一个EventBus

src/eventBus/index.ts

js 复制代码
import mitt from 'mitt'
const eventBus = mitt()
export default eventBus;

第二步:在main.js文件中引入这个eventBus,并通过RegistrableAppprops传给子应用(类似Vuex

js 复制代码
import eventBus from './eventBus/index'

registerMicroApps([
  {
    name: 'vue3-element-admin',
    entry: '//localhost:3001',
    container: '#container',
    activeRule: '/#/vue3-element-admin',
    props: {
      store,
      eventBus
    }
  }
],
)

第三步:在子应用的main.js文件中接收这个store,并通过createApp()的第二个参数props,将主应用的这个eventBus传递到子应用的根组件App.vue中。

js 复制代码
renderWithQiankun({
    mount(props) {
      appMount(props);
    },
  })
  
let app;
function appMount(props) {
  app = createApp(App, {
    parentStore: props?.store,
    parentEventBus: props?.eventBus
  })
  //...
}

第四步:在子应用的根组件App.vue文件中,通过props接收这个eventBus,并通过provite()将这个eventBus注入到所有子组件中

js 复制代码
setup(props) {
    provide('parentEventBus', props.parentEventBus)
}

第五步:在主应用的App.vue文件中,引入eventBus,订阅一个setUserName事件

js 复制代码
import eventBus from "./eventBus/index"

const userName : any = ref('')
eventBus.on('setUserName', (name) => {
  userName.value = name;
})

第六步:在子应用需要的子组件中,触发setUserName事件

js 复制代码
const userName = ref('')
  const parentEventBus = inject('parentEventBus')
  const changeUserName = () => {
    parentEventBus?.emit('setUserName', userName.value)
  }

注意:如果订阅事件的组件销毁了,则通信失败

使用 qiankun initGlobalState

第一步: 在主应用中创建一个全局状态

actions.setGlobalState()传入的对象,与原对象存在相同的key则修改value,原对象不存在相同的key则直接新增。

  • 微应用中只能修改已存在的一级属性
js 复制代码
import { registerMicroApps, start, initGlobalState } from 'qiankun'

const state = {
  a: 2,
  b: 2
}
const actions : MicroAppStateActions = initGlobalState(state);
actions.onGlobalStateChange((state, prev) => {
  console.log('主应用监听GlobalState:', state, prev)
})
actions.setGlobalState({
  c: 3, // 该属性会附加到state中
});

第二步:子应用直接使用props上的onGlobalStateChangesetGlobalState

  • 子应用上新增的key不生效
js 复制代码
props.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log('子应用监听GlobalState:', state, prev);
  });

  props.setGlobalState({
    a: 11
  })

  props.setGlobalState({
    b: 22
  })

  props.setGlobalState({
    d: 4, // 新增的id,不会加到state上。
  });
  
  props.setGlobalState({
    c: 33,
  });

综上所述,个人觉得使用Vuex/pinia实现应用间通信应该是最好的方式。

相关推荐
吴永琦(桂林电子科技大学)13 分钟前
HTML5
前端·html·html5
爱因斯坦乐15 分钟前
【HTML】纯前端网页小游戏-戳破彩泡
前端·javascript·html
恋猫de小郭21 分钟前
注意,暂时不要升级 MacOS ,Flutter/RN 等构建 ipa 可能会因 「ITMS-90048」This bundle is invalid 被拒绝
android·前端·flutter
大莲芒4 小时前
react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react17
前端·react.js·前端框架
木木黄木木6 小时前
html5炫酷3D文字效果项目开发实践
前端·3d·html5
Li_Ning217 小时前
【接口重复请求】axios通过AbortController解决页面切换过快,接口重复请求问题
前端
胡八一7 小时前
Window调试 ios 的 Safari 浏览器
前端·ios·safari
Dontla7 小时前
前端页面鼠标移动监控(鼠标运动、鼠标监控)鼠标节流处理、throttle、限制触发频率(setTimeout、clearInterval)
前端·javascript
再学一点就睡8 小时前
深拷贝与浅拷贝:代码世界里的永恒与瞬间
前端·javascript
CrimsonHu8 小时前
B站首页的 Banner 这么好看,我用原生 JS + 三大框架统统给你复刻一遍!
前端·javascript·css