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

相关推荐
轻口味31 分钟前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami34 分钟前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡1 小时前
lodash常用函数
前端·javascript
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235952 小时前
web复习(三)
前端
AiFlutter2 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
麦兜*2 小时前
轮播图带详情插件、uniApp插件
前端·javascript·uni-app·vue