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实现应用间通信应该是最好的方式。

相关推荐
小小小小宇34 分钟前
前端国际化看这一篇就够了
前端
大G哥38 分钟前
PHP标签+注释+html混写+变量
android·开发语言·前端·html·php
whoarethenext39 分钟前
html初识
前端·html
小小小小宇1 小时前
一个功能相对完善的前端 Emoji
前端
m0_627827521 小时前
vue中 vue.config.js反向代理
前端
Java&Develop1 小时前
onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
前端·spring boot·编辑器
白泽talk1 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师1 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
HhhDreamof_1 小时前
云贝餐饮 最新 V3 独立连锁版 全开源 多端源码 VUE 可二开
前端·vue.js·开源
Simaoya1 小时前
【vue】【element-plus】 el-date-picker使用cell-class-name进行标记,type=year不生效解决方法
前端·javascript·vue.js